9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] [PATCH] ptrap: implement attribute filters
@ 2020-12-05 16:52 kvik
  2020-12-05 17:32 ` ori
  0 siblings, 1 reply; 5+ messages in thread
From: kvik @ 2020-12-05 16:52 UTC (permalink / raw)
  To: 9front


This adds support for filtering plumbs based on message
attributes.  An example use case is to make a specific
acme instance display the manual pages produced by
man -b or plumbing the manual reference words:

	ptrap edit '.*' +action '^showdata' +filename '^/man/'
	
---

Works fine on my machine, but I'd appreciate some eyes
and testing from more prolific ptrap users than myself.

diff -r 52827b94aac8 sys/man/4/ptrap
--- a/sys/man/4/ptrap	Wed Dec 02 00:57:21 2020 +0100
+++ b/sys/man/4/ptrap	Sat Dec 05 17:37:27 2020 +0100
@@ -7,10 +7,7 @@
 .B ptrap
 .I port
 [\fB!\fR]\fIregexp\fR
-[
-.I port
-[\fB!\fR]\fIregexp\fR ...
-]
+[ +\fIattr\fR [\fB!\fR]\fIregexp\fR ... ] ...
 .SH DESCRIPTION
 .I Ptrap
 is a program that mounts itself over a
@@ -20,20 +17,20 @@
 and filters incoming messages according to the rules provided on the command line.
 .PP
 .I Ptrap
-accepts an arbitrary number of argument pairs; each pair consists of a port name
-.I port
-and a regular expression
-.I regexp
-(see
-.IR regexp (6)).
-Each incoming message that does not match
-.I regexp
-is discarded.
-The
-.I regexp
-can be optionally prefixed by
-.B !
-to indicate logical inversion (i.e. messages matching the regexp are discarded).
+accepts an arbitrary number of filters;
+each filter applies to a port, and may match over both the data and attributes of plumb messages.
+.PP
+A filter is formatted as a port name, a data filter, and a list of attribute filters.
+.PP
+The data filter is a
+.IR regex (6)
+that matches the plumbed data.
+The attribute filter consists of the attribute name prefixed with a '+', followed by a
+.IR regex (6)
+that matches the contents of the attribute.
+Any regex may be prefixed with a '!' in order to negate a match,
+causing all matches for that regex to be discarded.
+All parts of a filter must match in order for a plumb message to be forwarded.
 .SH EXAMPLES
 Start a 
 .IR sam (1)
@@ -52,6 +49,15 @@
 ptrap edit '!^/sys/src/9/'
 sam
 .EE
+.PP
+Start an
+.IR acme (1)
+instance instance dedicated to reading plumbed manual pages:
+.IP
+.EX
+ptrap edit '.*' +action '^showdata' +filename '^/man/'
+acme -c1
+.EE
 .SH SOURCE
 .B /sys/src/cmd/ptrap.c
 .SH SEE ALSO
diff -r 52827b94aac8 sys/src/cmd/ptrap.c
--- a/sys/src/cmd/ptrap.c	Wed Dec 02 00:57:21 2020 +0100
+++ b/sys/src/cmd/ptrap.c	Sat Dec 05 17:37:27 2020 +0100
@@ -8,6 +8,7 @@
 
 typedef struct IOProc IOProc;
 typedef struct PFilter PFilter;
+typedef struct FAttr FAttr;
 typedef struct PFid PFid;
 
 struct IOProc {
@@ -27,11 +28,19 @@
 };
 Qid rootqid = {.type QTDIR};
 
+struct FAttr {
+	char *name;
+	Reprog *filt;
+	int invert;
+	FAttr *next;
+};
+
 struct PFilter {
 	char *name;
 	Reprog *filt;
+	int invert;
+	FAttr *attr;
 	PFilter *next;
-	int invert;
 };
 PFilter *filters;
 
@@ -162,12 +171,32 @@
 }
 
 static int
+filter(PFilter *f, Plumbmsg *pm)
+{
+	FAttr *a;
+	char *value;
+
+	if(!(regexec(f->filt, pm->data, nil, 0) ^ f->invert))
+		return 0;
+	for(a = f->attr; a; a = a->next){
+		value = plumblookup(pm->attr, a->name);
+		if(value == nil)
+			return 0;
+		if(!(regexec(a->filt, value, nil, 0) ^ f->attr->invert))
+			return 0;
+	}
+	return 1;
+}
+
+static int
 filterread(Req *r, PFid *pf)
 {
 	int rc, len, more;
 	char *buf;
 	Plumbmsg *pm;
+	PFilter *f;
 	
+	f = pf->filter;
 	for(;;){
 		if(pf->msg != nil){
 			rc = r->ifcall.count;
@@ -194,7 +223,7 @@
 			len += rc;
 		}
 		free(buf);
-		if(regexec(pf->filter->filt, pm->data, nil, 0) ^ pf->filter->invert){
+		if(filter(f, pm)){
 			pf->msg = plumbpack(pm, &pf->msgn);
 			pf->msgp = 0;
 		}
@@ -341,7 +370,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s port regex [ port regex ... ]\n", argv0);
+	fprint(2, "usage: %s port regex [ +attr regex ... ] ...\n", argv0);
 	exits("usage");
 }
 
@@ -349,6 +378,7 @@
 threadmain(int argc, char **argv)
 {
 	PFilter *f;
+	FAttr *fa;
 	char *p;
 	int i;
 
@@ -357,19 +387,40 @@
 	}ARGEND;
 
 	if(argc == 0 || argc % 2) usage();
-	for(i = 0; i < argc; i += 2){
+	for(i = 0; i < argc; ){
+		p = argv[i++];
 		f = emalloc9p(sizeof(PFilter));
-		f->name = strdup(argv[i]);
-		p = argv[i+1];
-		if(*p == '!'){
+		f->name = estrdup9p(p);
+		p = argv[i++];
+		if(p[0] == '!'){
 			p++;
 			f->invert = 1;
 		}
-		f->filt = regcomp(p);
-		if(f->filt == nil)
-			sysfatal("%r");
+		if((f->filt = regcomp(p)) == nil)
+			sysfatal("regcomp: %r");
 		f->next = filters;
 		filters = f;
+
+next:
+		p = argv[i++];
+		if(p == nil || p[0] != '+'){
+			i--;
+			continue;
+		}
+		p++;
+		fa = emalloc9p(sizeof(FAttr));
+		fa->name = estrdup9p(p);
+		p = argv[i++];
+		if(p[0] == '!'){
+			p++;
+			fa->invert = 1;
+		}
+		if((fa->filt = regcomp(p)) == nil)
+			sysfatal("regcomp: %r");
+		fa->next = f->attr;
+		f->attr = fa;
+
+		goto next;
 	}
 	threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] [PATCH] ptrap: implement attribute filters
  2020-12-05 16:52 [9front] [PATCH] ptrap: implement attribute filters kvik
@ 2020-12-05 17:32 ` ori
  2020-12-05 19:07   ` kvik
  0 siblings, 1 reply; 5+ messages in thread
From: ori @ 2020-12-05 17:32 UTC (permalink / raw)
  To: kvik, 9front

Quoth kvik@a-b.xyz:
> 
> This adds support for filtering plumbs based on message
> attributes.  An example use case is to make a specific
> acme instance display the manual pages produced by
> man -b or plumbing the manual reference words:
> 
> 	ptrap edit '.*' +action '^showdata' +filename '^/man/'
> 	
> ---
> +
> +next:
> +		p = argv[i++];
> +		if(p == nil || p[0] != '+'){
> +			i--;
> +			continue;
> +		}
> +		p++;
> +		fa = emalloc9p(sizeof(FAttr));
> +		fa->name = estrdup9p(p);
> +		p = argv[i++];
> +		if(p[0] == '!'){
> +			p++;
> +			fa->invert = 1;
> +		}
> +		if((fa->filt = regcomp(p)) == nil)
> +			sysfatal("regcomp: %r");
> +		fa->next = f->attr;
> +		f->attr = fa;
> +
> +		goto next;
>  	}
>  	threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);
>  
> 

Testing now, though I don't use the filtering *that* heavily,
I mainly use it to prevent acme from becoming an editor.

Looking over the code, only thought is that this bit may read
better as a nested loop, like:

	for(; i < argc; i++){
		...

	}

Other than that, I think this looks good.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] [PATCH] ptrap: implement attribute filters
  2020-12-05 17:32 ` ori
@ 2020-12-05 19:07   ` kvik
  2020-12-06  0:49     ` ori
  0 siblings, 1 reply; 5+ messages in thread
From: kvik @ 2020-12-05 19:07 UTC (permalink / raw)
  To: 9front


Quoth ori@eigenstate.org:
> Looking over the code, only thought is that this bit may read
> better as a nested loop, like:

That's quite true.  Readability++ version follows.

diff -r 52827b94aac8 sys/man/4/ptrap
--- a/sys/man/4/ptrap	Wed Dec 02 00:57:21 2020 +0100
+++ b/sys/man/4/ptrap	Sat Dec 05 19:40:38 2020 +0100
@@ -7,10 +7,7 @@
 .B ptrap
 .I port
 [\fB!\fR]\fIregexp\fR
-[
-.I port
-[\fB!\fR]\fIregexp\fR ...
-]
+[ +\fIattr\fR [\fB!\fR]\fIregexp\fR ... ] ...
 .SH DESCRIPTION
 .I Ptrap
 is a program that mounts itself over a
@@ -20,20 +17,20 @@
 and filters incoming messages according to the rules provided on the command line.
 .PP
 .I Ptrap
-accepts an arbitrary number of argument pairs; each pair consists of a port name
-.I port
-and a regular expression
-.I regexp
-(see
-.IR regexp (6)).
-Each incoming message that does not match
-.I regexp
-is discarded.
-The
-.I regexp
-can be optionally prefixed by
-.B !
-to indicate logical inversion (i.e. messages matching the regexp are discarded).
+accepts an arbitrary number of filters;
+each filter applies to a port, and may match over both the data and attributes of plumb messages.
+.PP
+A filter is formatted as a port name, a data filter, and a list of attribute filters.
+.PP
+The data filter is a
+.IR regex (6)
+that matches the plumbed data.
+The attribute filter consists of the attribute name prefixed with a '+', followed by a
+.IR regex (6)
+that matches the contents of the attribute.
+Any regex may be prefixed with a '!' in order to negate a match,
+causing all matches for that regex to be discarded.
+All parts of a filter must match in order for a plumb message to be forwarded.
 .SH EXAMPLES
 Start a 
 .IR sam (1)
@@ -52,6 +49,15 @@
 ptrap edit '!^/sys/src/9/'
 sam
 .EE
+.PP
+Start an
+.IR acme (1)
+instance instance dedicated to reading plumbed manual pages:
+.IP
+.EX
+ptrap edit '.*' +action '^showdata' +filename '^/man/'
+acme -c1
+.EE
 .SH SOURCE
 .B /sys/src/cmd/ptrap.c
 .SH SEE ALSO
diff -r 52827b94aac8 sys/src/cmd/ptrap.c
--- a/sys/src/cmd/ptrap.c	Wed Dec 02 00:57:21 2020 +0100
+++ b/sys/src/cmd/ptrap.c	Sat Dec 05 19:40:38 2020 +0100
@@ -8,6 +8,7 @@
 
 typedef struct IOProc IOProc;
 typedef struct PFilter PFilter;
+typedef struct FAttr FAttr;
 typedef struct PFid PFid;
 
 struct IOProc {
@@ -27,11 +28,19 @@
 };
 Qid rootqid = {.type QTDIR};
 
+struct FAttr {
+	char *name;
+	Reprog *filt;
+	int invert;
+	FAttr *next;
+};
+
 struct PFilter {
 	char *name;
 	Reprog *filt;
+	int invert;
+	FAttr *attr;
 	PFilter *next;
-	int invert;
 };
 PFilter *filters;
 
@@ -162,12 +171,32 @@
 }
 
 static int
+filter(PFilter *f, Plumbmsg *pm)
+{
+	FAttr *a;
+	char *value;
+
+	if(!(regexec(f->filt, pm->data, nil, 0) ^ f->invert))
+		return 0;
+	for(a = f->attr; a; a = a->next){
+		value = plumblookup(pm->attr, a->name);
+		if(value == nil)
+			return 0;
+		if(!(regexec(a->filt, value, nil, 0) ^ f->attr->invert))
+			return 0;
+	}
+	return 1;
+}
+
+static int
 filterread(Req *r, PFid *pf)
 {
 	int rc, len, more;
 	char *buf;
 	Plumbmsg *pm;
+	PFilter *f;
 	
+	f = pf->filter;
 	for(;;){
 		if(pf->msg != nil){
 			rc = r->ifcall.count;
@@ -194,7 +223,7 @@
 			len += rc;
 		}
 		free(buf);
-		if(regexec(pf->filter->filt, pm->data, nil, 0) ^ pf->filter->invert){
+		if(filter(f, pm)){
 			pf->msg = plumbpack(pm, &pf->msgn);
 			pf->msgp = 0;
 		}
@@ -341,7 +370,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s port regex [ port regex ... ]\n", argv0);
+	fprint(2, "usage: %s port regex [ +attr regex ... ] ...\n", argv0);
 	exits("usage");
 }
 
@@ -349,6 +378,7 @@
 threadmain(int argc, char **argv)
 {
 	PFilter *f;
+	FAttr *fa;
 	char *p;
 	int i;
 
@@ -357,19 +387,33 @@
 	}ARGEND;
 
 	if(argc == 0 || argc % 2) usage();
-	for(i = 0; i < argc; i += 2){
+	for(i = 0; i+1 < argc;){
+		p = argv[i];
 		f = emalloc9p(sizeof(PFilter));
-		f->name = strdup(argv[i]);
+		f->name = estrdup9p(p);
 		p = argv[i+1];
-		if(*p == '!'){
+		if(p[0] == '!'){
 			p++;
 			f->invert = 1;
 		}
-		f->filt = regcomp(p);
-		if(f->filt == nil)
-			sysfatal("%r");
+		if((f->filt = regcomp(p)) == nil)
+			sysfatal("regcomp: %r");
 		f->next = filters;
 		filters = f;
+		for(i += 2; p = argv[i], i+1 < argc && p[0] == '+'; i += 2){
+			p++;
+			fa = emalloc9p(sizeof(FAttr));
+			fa->name = estrdup9p(p);
+			p = argv[i+1];
+			if(p[0] == '!'){
+				p++;
+				fa->invert = 1;
+			}
+			if((fa->filt = regcomp(p)) == nil)
+				sysfatal("regcomp: %r");
+			fa->next = f->attr;
+			f->attr = fa;
+		}
 	}
 	threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] [PATCH] ptrap: implement attribute filters
  2020-12-05 19:07   ` kvik
@ 2020-12-06  0:49     ` ori
  2020-12-06 20:55       ` kvik
  0 siblings, 1 reply; 5+ messages in thread
From: ori @ 2020-12-06  0:49 UTC (permalink / raw)
  To: kvik, 9front

Quoth kvik@a-b.xyz:
> 
> Quoth ori@eigenstate.org:
> > Looking over the code, only thought is that this bit may read
> > better as a nested loop, like:
> 
> That's quite true.  Readability++ version follows.

ok from me.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] [PATCH] ptrap: implement attribute filters
  2020-12-06  0:49     ` ori
@ 2020-12-06 20:55       ` kvik
  0 siblings, 0 replies; 5+ messages in thread
From: kvik @ 2020-12-06 20:55 UTC (permalink / raw)
  To: 9front


Commited.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-12-06 20:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-05 16:52 [9front] [PATCH] ptrap: implement attribute filters kvik
2020-12-05 17:32 ` ori
2020-12-05 19:07   ` kvik
2020-12-06  0:49     ` ori
2020-12-06 20:55       ` kvik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).