📄 match.c
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <regexp.h>#include <thread.h>#include <plumb.h>#include "plumber.h"static char*nonnil(char *s){ if(s == nil) return ""; return s;}intverbis(int obj, Plumbmsg *m, Rule *r){ switch(obj){ default: fprint(2, "unimplemented 'is' object %d\n", obj); break; case OData: return strcmp(m->data, r->qarg) == 0; case ODst: return strcmp(m->dst, r->qarg) == 0; case OType: return strcmp(m->type, r->qarg) == 0; case OWdir: return strcmp(m->wdir, r->qarg) == 0; case OSrc: return strcmp(m->src, r->qarg) == 0; } return 0;}static voidsetvar(Resub rs[10], char *match[10]){ int i, n; for(i=0; i<10; i++){ free(match[i]); match[i] = nil; } for(i=0; i<10 && rs[i].sp!=nil; i++){ n = rs[i].ep-rs[i].sp; match[i] = emalloc(n+1); memmove(match[i], rs[i].sp, n); match[i][n] = '\0'; }}intclickmatch(Reprog *re, char *text, Resub rs[10], int click){ char *clickp; int i, w; Rune r; /* click is in characters, not bytes */ for(i=0; i<click && text[i]!='\0'; i+=w) w = chartorune(&r, text+i); clickp = text+i; for(i=0; i<=click; i++){ memset(rs, 0, 10*sizeof(Resub)); if(regexec(re, text+i, rs, 10)) if(rs[0].sp<=clickp && clickp<=rs[0].ep) return 1; } return 0;}intverbmatches(int obj, Plumbmsg *m, Rule *r, Exec *e){ Resub rs[10]; char *clickval, *alltext; int p0, p1, ntext; memset(rs, 0, sizeof rs); ntext = -1; switch(obj){ default: fprint(2, "unimplemented 'matches' object %d\n", obj); break; case OData: clickval = plumblookup(m->attr, "click"); if(clickval == nil){ alltext = m->data; ntext = m->ndata; goto caseAlltext; } if(!clickmatch(r->regex, m->data, rs, atoi(clickval))) break; p0 = rs[0].sp - m->data; p1 = rs[0].ep - m->data; if(e->p0 >=0 && !(p0==e->p0 && p1==e->p1)) break; e->clearclick = 1; e->setdata = 1; e->p0 = p0; e->p1 = p1; setvar(rs, e->match); return 1; case ODst: alltext = m->dst; goto caseAlltext; case OType: alltext = m->type; goto caseAlltext; case OWdir: alltext = m->wdir; goto caseAlltext; case OSrc: alltext = m->src; /* fall through */ caseAlltext: /* must match full text */ if(ntext < 0) ntext = strlen(alltext); if(!regexec(r->regex, alltext, rs, 10) || rs[0].sp!=alltext || rs[0].ep!=alltext+ntext) break; setvar(rs, e->match); return 1; } return 0;}intisfile(char *file, ulong maskon, ulong maskoff){ Dir *d; int mode; d = dirstat(file); if(d == nil) return 0; mode = d->mode; free(d); if((mode & maskon) == 0) return 0; if(mode & maskoff) return 0; return 1;}char*absolute(char *dir, char *file){ char *p; if(file[0] == '/') return estrdup(file); p = emalloc(strlen(dir)+1+strlen(file)+1); sprint(p, "%s/%s", dir, file); return cleanname(p);}intverbisfile(int obj, Plumbmsg *m, Rule *r, Exec *e, ulong maskon, ulong maskoff, char **var){ char *file; switch(obj){ default: fprint(2, "unimplemented 'isfile' object %d\n", obj); break; case OArg: file = absolute(m->wdir, expand(e, r->arg, nil)); if(isfile(file, maskon, maskoff)){ *var = file; return 1; } free(file); break; case OData: case OWdir: file = absolute(m->wdir, obj==OData? m->data : m->wdir); if(isfile(file, maskon, maskoff)){ *var = file; return 1; } free(file); break; } return 0;}intverbset(int obj, Plumbmsg *m, Rule *r, Exec *e){ char *new; switch(obj){ default: fprint(2, "unimplemented 'is' object %d\n", obj); break; case OData: new = estrdup(expand(e, r->arg, nil)); m->ndata = strlen(new); free(m->data); m->data = new; e->p0 = -1; e->p1 = -1; e->setdata = 0; return 1; case ODst: new = estrdup(expand(e, r->arg, nil)); free(m->dst); m->dst = new; return 1; case OType: new = estrdup(expand(e, r->arg, nil)); free(m->type); m->type = new; return 1; case OWdir: new = estrdup(expand(e, r->arg, nil)); free(m->wdir); m->wdir = new; return 1; case OSrc: new = estrdup(expand(e, r->arg, nil)); free(m->src); m->src = new; return 1; } return 0;}intverbadd(int obj, Plumbmsg *m, Rule *r, Exec *e){ switch(obj){ default: fprint(2, "unimplemented 'add' object %d\n", obj); break; case OAttr: m->attr = plumbaddattr(m->attr, plumbunpackattr(expand(e, r->arg, nil))); return 1; } return 0;}intverbdelete(int obj, Plumbmsg *m, Rule *r, Exec *e){ char *a; switch(obj){ default: fprint(2, "unimplemented 'delete' object %d\n", obj); break; case OAttr: a = expand(e, r->arg, nil); if(plumblookup(m->attr, a) == nil) break; m->attr = plumbdelattr(m->attr, a); return 1; } return 0;}intmatchpat(Plumbmsg *m, Exec *e, Rule *r){ switch(r->verb){ default: fprint(2, "unimplemented verb %d\n", r->verb); break; case VAdd: return verbadd(r->obj, m, r, e); case VDelete: return verbdelete(r->obj, m, r, e); case VIs: return verbis(r->obj, m, r); case VIsdir: return verbisfile(r->obj, m, r, e, DMDIR, 0, &e->dir); case VIsfile: return verbisfile(r->obj, m, r, e, ~DMDIR, DMDIR, &e->file); case VMatches: return verbmatches(r->obj, m, r, e); case VSet: verbset(r->obj, m, r, e); return 1; } return 0;}voidfreeexec(Exec *exec){ int i; if(exec == nil) return; free(exec->dir); free(exec->file); for(i=0; i<10; i++) free(exec->match[i]); free(exec);}Exec*newexec(Plumbmsg *m){ Exec *exec; exec = emalloc(sizeof(Exec)); exec->msg = m; exec->p0 = -1; exec->p1 = -1; return exec;}voidrewrite(Plumbmsg *m, Exec *e){ Plumbattr *a, *prev; if(e->clearclick){ prev = nil; for(a=m->attr; a!=nil; a=a->next){ if(strcmp(a->name, "click") == 0){ if(prev == nil) m->attr = a->next; else prev->next = a->next; free(a->name); free(a->value); free(a); break; } prev = a; } if(e->setdata){ free(m->data); m->data = estrdup(expand(e, "$0", nil)); m->ndata = strlen(m->data); } }}char**buildargv(char *s, Exec *e){ char **av; int ac; ac = 0; av = nil; for(;;){ av = erealloc(av, (ac+1) * sizeof(char*)); av[ac] = nil; while(*s==' ' || *s=='\t') s++; if(*s == '\0') break; av[ac++] = estrdup(expand(e, s, &s)); } return av;}Exec*matchruleset(Plumbmsg *m, Ruleset *rs){ int i; Exec *exec; if(m->dst!=nil && m->dst[0]!='\0' && rs->port!=nil && strcmp(m->dst, rs->port)!=0) return nil; exec = newexec(m); for(i=0; i<rs->npat; i++) if(!matchpat(m, exec, rs->pat[i])){ freeexec(exec); return nil; } if(rs->port!=nil && (m->dst==nil || m->dst[0]=='\0')){ free(m->dst); m->dst = estrdup(rs->port); } rewrite(m, exec); return exec;}enum{ NARGS = 100, NARGCHAR = 8*1024, EXECSTACK = 4096+(NARGS+1)*sizeof(char*)+NARGCHAR};/* copy argv to stack and free the incoming strings, so we don't leak argument vectors */voidstackargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR]){ int i, n; char *s, *a; s = args; for(i=0; i<NARGS; i++){ a = inargv[i]; if(a == nil) break; n = strlen(a)+1; if((s-args)+n >= NARGCHAR) /* too many characters */ break; argv[i] = s; memmove(s, a, n); s += n; free(a); } argv[i] = nil;}voidexecproc(void *v){ char **av; char buf[1024], *args[NARGS+1], argc[NARGCHAR]; rfork(RFFDG); close(0); open("/dev/null", OREAD); av = v; stackargv(av, args, argc); free(av); procexec(nil, args[0], args); if(args[0][0]!='/' && strncmp(args[0], "./", 2)!=0 && strncmp(args[0], "../", 3)!=0) snprint(buf, sizeof buf, "/bin/%s", args[0]); procexec(nil, buf, args); threadexits("can't exec");}char*startup(Ruleset *rs, Exec *e){ char **argv; int i; if(rs != nil) for(i=0; i<rs->nact; i++){ if(rs->act[i]->verb == VStart) goto Found; if(rs->act[i]->verb == VClient){ if(e->msg->dst==nil || e->msg->dst[0]=='\0') return "no port for \"client\" rule"; e->holdforclient = 1; goto Found; } } return "no start action for plumb message";Found: argv = buildargv(rs->act[i]->arg, e); if(argv[0] == nil) return "empty argument list"; proccreate(execproc, argv, EXECSTACK); return nil;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -