|  | /* The IGEN simulator generator for GDB, the GNU Debugger. | 
|  |  | 
|  | Copyright 2002-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | Contributed by Andrew Cagney. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include "misc.h" | 
|  | #include "lf.h" | 
|  | #include "filter.h" | 
|  |  | 
|  | struct _filter | 
|  | { | 
|  | char *member; | 
|  | filter *next; | 
|  | }; | 
|  |  | 
|  |  | 
|  | void | 
|  | filter_parse (filter **filters, const char *filt) | 
|  | { | 
|  | while (strlen (filt) > 0) | 
|  | { | 
|  | filter *new_filter; | 
|  | filter **last; | 
|  | /* break out a member of the filter list */ | 
|  | const char *flag = filt; | 
|  | unsigned /*size_t */ len; | 
|  | filt = strchr (filt, ','); | 
|  | if (filt == NULL) | 
|  | { | 
|  | filt = strchr (flag, '\0'); | 
|  | len = strlen (flag); | 
|  | } | 
|  | else | 
|  | { | 
|  | len = filt - flag; | 
|  | filt = filt + 1; | 
|  | } | 
|  | /* find an insertion point - sorted order */ | 
|  | last = filters; | 
|  | while (*last != NULL && strncmp (flag, (*last)->member, len) > 0) | 
|  | last = &(*last)->next; | 
|  | if (*last != NULL | 
|  | && strncmp (flag, (*last)->member, len) == 0 | 
|  | && strlen ((*last)->member) == len) | 
|  | continue;		/* duplicate */ | 
|  | /* create an entry for that member */ | 
|  | new_filter = ZALLOC (filter); | 
|  | new_filter->member = NZALLOC (char, len + 1); | 
|  | strncpy (new_filter->member, flag, len); | 
|  | /* insert it */ | 
|  | new_filter->next = *last; | 
|  | *last = new_filter; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | filter_add (filter **set, const filter *add) | 
|  | { | 
|  | while (add != NULL) | 
|  | { | 
|  | int cmp; | 
|  | if (*set == NULL) | 
|  | cmp = 1;		/* set->member > add->member */ | 
|  | else | 
|  | cmp = strcmp ((*set)->member, add->member); | 
|  | if (cmp > 0) | 
|  | { | 
|  | /* insert it here */ | 
|  | filter *new = ZALLOC (filter); | 
|  | new->member = NZALLOC (char, strlen (add->member) + 1); | 
|  | strcpy (new->member, add->member); | 
|  | new->next = *set; | 
|  | *set = new; | 
|  | add = add->next; | 
|  | } | 
|  | else if (cmp == 0) | 
|  | { | 
|  | /* already in set */ | 
|  | add = add->next; | 
|  | } | 
|  | else			/* cmp < 0 */ | 
|  | { | 
|  | /* not reached insertion point */ | 
|  | set = &(*set)->next; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | filter_is_subset (const filter *superset, const filter *subset) | 
|  | { | 
|  | while (1) | 
|  | { | 
|  | int cmp; | 
|  | if (subset == NULL) | 
|  | return 1; | 
|  | if (superset == NULL) | 
|  | return 0;		/* subset isn't finished */ | 
|  | cmp = strcmp (subset->member, superset->member); | 
|  | if (cmp < 0) | 
|  | return 0;		/* not found */ | 
|  | else if (cmp == 0) | 
|  | subset = subset->next;	/* found */ | 
|  | else if (cmp > 0) | 
|  | superset = superset->next;	/* later in list? */ | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | filter_is_common (const filter *l, const filter *r) | 
|  | { | 
|  | while (1) | 
|  | { | 
|  | int cmp; | 
|  | if (l == NULL) | 
|  | return 0; | 
|  | if (r == NULL) | 
|  | return 0; | 
|  | cmp = strcmp (l->member, r->member); | 
|  | if (cmp < 0) | 
|  | l = l->next; | 
|  | else if (cmp == 0) | 
|  | return 1;		/* common member */ | 
|  | else if (cmp > 0) | 
|  | r = r->next; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | filter_is_member (const filter *filt, const char *flag) | 
|  | { | 
|  | int index = 1; | 
|  | while (filt != NULL) | 
|  | { | 
|  | if (strcmp (flag, filt->member) == 0) | 
|  | return index; | 
|  | filt = filt->next; | 
|  | index++; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | is_filtered_out (const filter *filters, const char *flags) | 
|  | { | 
|  | while (strlen (flags) > 0) | 
|  | { | 
|  | int present; | 
|  | const filter *filt = filters; | 
|  | /* break the string up */ | 
|  | const char *end = strchr (flags, ','); | 
|  | const char *next; | 
|  | unsigned /*size_t */ len; | 
|  | if (end == NULL) | 
|  | { | 
|  | end = strchr (flags, '\0'); | 
|  | next = end; | 
|  | } | 
|  | else | 
|  | { | 
|  | next = end + 1; | 
|  | } | 
|  | len = end - flags; | 
|  | /* check that it is present */ | 
|  | present = 0; | 
|  | filt = filters; | 
|  | while (filt != NULL) | 
|  | { | 
|  | if (strncmp (flags, filt->member, len) == 0 | 
|  | && strlen (filt->member) == len) | 
|  | { | 
|  | present = 1; | 
|  | break; | 
|  | } | 
|  | filt = filt->next; | 
|  | } | 
|  | if (!present) | 
|  | return 1; | 
|  | flags = next; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | const char * | 
|  | filter_next (const filter *set, const char *member) | 
|  | { | 
|  | while (set != NULL) | 
|  | { | 
|  | if (strcmp (set->member, member) > 0) | 
|  | return set->member; | 
|  | set = set->next; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | dump_filter (lf *file, | 
|  | const char *prefix, | 
|  | const filter *set, | 
|  | const char *suffix) | 
|  | { | 
|  | const char *member; | 
|  | lf_printf (file, "%s", prefix); | 
|  | member = filter_next (set, ""); | 
|  | if (member != NULL) | 
|  | { | 
|  | while (1) | 
|  | { | 
|  | lf_printf (file, "%s", member); | 
|  | member = filter_next (set, member); | 
|  | if (member == NULL) | 
|  | break; | 
|  | lf_printf (file, ","); | 
|  | } | 
|  | } | 
|  | lf_printf (file, "%s", suffix); | 
|  | } | 
|  |  | 
|  |  | 
|  | #ifdef MAIN | 
|  | int | 
|  | main (int argc, char **argv) | 
|  | { | 
|  | filter *subset = NULL; | 
|  | filter *superset = NULL; | 
|  | lf *l; | 
|  | int i; | 
|  | if (argc < 2) | 
|  | { | 
|  | printf ("Usage: filter <subset> <filter> ...\n"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | /* load the filter up */ | 
|  | filter_parse (&subset, argv[1]); | 
|  | for (i = 2; i < argc; i++) | 
|  | filter_parse (&superset, argv[i]); | 
|  |  | 
|  | /* dump various info */ | 
|  | l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-filter"); | 
|  |  | 
|  | /* subset */ | 
|  | { | 
|  | dump_filter (l, "{", subset, " }"); | 
|  | if (filter_is_subset (superset, subset)) | 
|  | lf_printf (l, " subset of "); | 
|  | else | 
|  | lf_printf (l, " !subset of "); | 
|  | dump_filter (l, "{", superset, " }"); | 
|  | lf_printf (l, "\n"); | 
|  | } | 
|  | /* intersection */ | 
|  | { | 
|  | dump_filter (l, "{", subset, " }"); | 
|  | if (filter_is_common (subset, superset)) | 
|  | lf_printf (l, " intersects "); | 
|  | else | 
|  | lf_printf (l, " !intersects "); | 
|  | dump_filter (l, "{", superset, " }"); | 
|  | lf_printf (l, "\n"); | 
|  | } | 
|  | /* membership */ | 
|  | { | 
|  | filter *memb = subset; | 
|  | while (memb != NULL) | 
|  | { | 
|  | lf_printf (l, "%s", memb->member); | 
|  | if (filter_is_member (superset, memb->member)) | 
|  | lf_printf (l, " in "); | 
|  | else | 
|  | lf_printf (l, " !in "); | 
|  | dump_filter (l, "{", superset, " }"); | 
|  | lf_printf (l, "\n"); | 
|  | memb = memb->next; | 
|  | } | 
|  | } | 
|  | /* addition */ | 
|  | { | 
|  | filter *add = NULL; | 
|  | filter_add (&add, superset); | 
|  | filter_add (&add, subset); | 
|  | dump_filter (l, "{", add, " }"); | 
|  | lf_printf (l, " = "); | 
|  | dump_filter (l, "{", subset, " }"); | 
|  | lf_printf (l, " + "); | 
|  | dump_filter (l, "{", superset, " }"); | 
|  | lf_printf (l, "\n"); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | #endif |