#include #include #include /* Works with the following plumb rule for Ocaml errors: type is text data matches 'File "([.a-zA-Z¡-￿0-9_/+\-]*[a-zA-Z¡-￿0-9_/+\-])", line ([0-9]+), characters ([0-9]+)-([0-9]+).*' arg isfile $1 data set $file attr add line=$2 attr add schar=$3 attr add echar=$4 plumb to mladdr */ enum MSG { LINE, SCHAR, ECHAR, NMSG, }; char *msgs[] = { [LINE] "line", [SCHAR] "schar", [ECHAR] "echar", }; int unpack(char **attrs, Plumbmsg *msg) { Plumbattr *attr; int i; attr = msg->attr; for(i = 0; i < NMSG; i++){ if(attr == nil){ syslog(0, "mladdr", "Bad msg: Not enough attributes"); return -1; } if(strcmp(attr->name, msgs[i]) != 0){ syslog(0, "mladdr", "Bad msg: looking for %s but got %s", msgs[i], attr->name); return -1; } attrs[i] = attr->value; attr = attr->next; } return 0; } void doplumb(int infd, int outfd) { static char addrbuf[1024]; static Plumbattr outattr = { .name "addr", .value addrbuf, }; static Plumbmsg outmsg = { .src "mladdr", .dst "edit", .type "text", .attr &outattr, }; Plumbmsg *msg; char *attrs[3]; long line; for(;;){ msg = plumbrecv(infd); if(msg == nil){ syslog(0, "mladdr", "Bad message: %r\n"); return; } if(unpack(attrs, msg) < 0) continue; line = strtol(attrs[LINE], nil, 0) - 1; outmsg.data = msg->data; outmsg.ndata = msg->ndata; seprint(addrbuf, addrbuf+sizeof(addrbuf), "%ld+#%s,%ld+#%s" , line, attrs[SCHAR], line, attrs[ECHAR]); plumbsend(outfd, &outmsg); plumbfree(msg); } } int eplumbopen(char *port, int mode) { int fd; fd = plumbopen(port, mode); if(fd < 0){ fprint(2, "Could not open plumb port: %r\n"); exits("clogged"); } return fd; } void main(void) { int infd, outfd; close(0); close(1); infd = eplumbopen("mladdr", OREAD); outfd = eplumbopen("send", OWRITE); switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){ case -1: fprint(2, "Could not fork child: %r\n"); exits("rfork"); case 0: close(2); doplumb(infd, outfd); break; } exits(nil); }