* global options:
* --stdin-monitor quit if stdin becomes readable
*
+ * redaction mode options:
+ *
+ * --redaction <str>... --suppress do not print these
+ * --redaction <str>... --show print these normally
+ *
+ * Longest matching <str>... applies. Later identical
+ * <str>... paths override earlier ones.
+ *
+ * --new-redactions resets everything to default (which is --show)
+ *
+ * Every device specified after --new-redactions gets the new
+ * set of redactions, which includes even redactions specified
+ * _after_ the device but _before_ the next --new-redactions.
+ * It is not possible to selectively edit the redactions list;
+ * devices which need different redaction lists need them
+ * respecifying.
+ *
* per-device options (applies only to next device):
* --label LABEL use LABEL instead of path in redacted output
*
typedef const ModeInfo *Mode;
typedef const KindInfo *Kind;
+typedef enum { RA_Show, RA_IntermediateNode, RA_Suppress } RedactionAction;
+
+typedef struct RedactionNode {
+ const char *str;
+ void *children; /* tsearch tree of RedactionNodes */
+ RedactionAction act;
+} RedactionNode;
+
struct ModeInfo {
void (*evdev_event)(Device *d, const struct input_event *ie);
void (*evdev_readable)(Device *d);
typedef struct {
int elide;
-} DeviceFlags;
+ RedactionNode redactions; /* root; .str is 0 and irrelevant */
+} DeviceOptions;
typedef struct {
struct hiddev_field_info fi;
const char *label;
int fd;
const KindInfo *kind;
- DeviceFlags flags;
+ DeviceOptions opts;
union {
struct {
void *froot;
static Kind kind;
static int grab, stdinmonitor;
static const char *expect_sysfs, *label;
-static DeviceFlags dflags= { 1 };
+static DeviceOptions dopts;
static int ndevices;
static Device *devices;
if (!f)
return 0;
- if (!d->flags.elide)
+ if (!d->opts.elide)
return 0;
unsigned relevant_flags= f->fi.flags &
/*---------- mode redact ----------*/
+static int redaction_node_compar(const void *a_v, const void *b_v) {
+ const RedactionNode *a=a_v, *b=b_v;
+ return strcmp(a->str, b->str);
+}
+
+static RedactionNode *redact_find_node(int nstrs, const char *strs[nstrs]) {
+ RedactionNode key, *lastfound, *search;
+ void **rn_vp;
+
+ lastfound= search= &dopts.redactions;
+ for (;;) {
+ if (!nstrs) return lastfound;
+ key.str= strs[0];
+ rn_vp= tfind(&key, &search->children, redaction_node_compar);
+ if (!rn_vp) return lastfound;
+ search= *rn_vp;
+ if (search->act != RA_IntermediateNode)
+ lastfound= search;
+ strs++;
+ nstrs--;
+ }
+}
+
static void redact_redacted(Device *d, int nstrs, const char *strs[nstrs],
int value) {
int i;
-
+ RedactionNode *rn;
+
+ rn= redact_find_node(nstrs, strs);
+ switch (rn->act) {
+ case RA_Show: break;
+ case RA_Suppress: return;
+ default: abort();
+ }
+
printf("%s %d", d->label, value);
for (i=0; i<nstrs; i++)
printf(" %s", strs[i]);
redact_redacted, dump_died, mainloop
};
+static void redaction(const char ***argv) {
+ RedactionNode *path, *newnode;
+ void **searched;
+ const char *arg;
+
+ path= &dopts.redactions;
+ for (;;) {
+ arg= *++(*argv);
+ if (!arg) badusage("missing str or action for --redaction");
+ if (arg[0]=='-') break;
+ newnode= mmalloc(sizeof(*newnode));
+ newnode->str= arg;
+ searched= tsearch(newnode, &path->children, redaction_node_compar);
+ if (!searched) diee("allocate new redaction node");
+ if (*searched == newnode) {
+ newnode->children= 0;
+ newnode->act= RA_IntermediateNode;
+ path= newnode;
+ } else {
+ free(newnode);
+ path= *searched;
+ }
+ }
+ if (!strcmp(arg,"--suppress")) {
+ path->act= RA_Suppress;
+ } else if (!strcmp(arg,"--show")) {
+ path->act= RA_Show;
+ } else {
+ badusage("unknown or missing action for --redaction");
+ }
+}
+
/*---------- main program ----------*/
static void getdevice(const char *path) {
d->path= mstrdup(path);
d->fd= open(path, O_RDONLY); if (d->fd<0) diee("%s: failed to open",path);
d->kind= kind;
- d->flags= dflags;
+ d->opts= dopts;
if (label) {
d->label= label;
mode= &mode_dump;
kind= &kind_evdev;
+ dopts.elide= 1;
while ((arg= *++argv)) {
if (arg[0] != '-') {
else if (!strcmp(arg,"--label")) {
if (!(label= *++argv)) badusage("missing arg for --expect-sysfs");
}
+ else if (!strcmp(arg,"--redaction")) {
+ redaction(&argv);
+ }
+ else if (!strcmp(arg,"--new-redactions")) {
+ dopts.redactions.children= 0;
+ dopts.redactions.act= RA_Show;
+ }
else if (!strcmp(arg,"--dump-raw")) { mode= &mode_dump; }
else if (!strcmp(arg,"--redact")) { mode= &mode_redact; }
else if (!strcmp(arg,"--evdev")) { kind= &kind_evdev; }
else if (!strcmp(arg,"--hiddev")) { kind= &kind_hiddev; }
else if (!strcmp(arg,"--grab")) { grab= 1; }
else if (!strcmp(arg,"--no-grab")) { grab= 0; }
- else if (!strcmp(arg,"--show-unchanged")) { dflags.elide= 0; }
- else if (!strcmp(arg,"--elide-unchanged")) { dflags.elide= 1; }
+ else if (!strcmp(arg,"--show-unchanged")) { dopts.elide= 0; }
+ else if (!strcmp(arg,"--elide-unchanged")) { dopts.elide= 1; }
else if (!strcmp(arg,"--stdin-monitor")) { stdinmonitor= 1; }
else badusage("unknown option");
}