mpick: add pipes and file redirection

pull/174/head
Duncaen 5 years ago committed by Leah Neukirchen
parent eec6a4ebfd
commit 401aa88752

@ -96,6 +96,9 @@ tests are given by the following EBNF:
| <expr> && <expr> -- conjunction | <expr> && <expr> -- conjunction
| ! <expr> -- negation | ! <expr> -- negation
| ( <expr> ) | ( <expr> )
| <expr> "|" <str> -- pipe current mail to command
| <expr> ">>" <str> -- append current mail to file
| <expr> ">" <str> -- write current mail to file
| <flagprop> | <flagprop>
| <timeprop> <numop> <dur> | <timeprop> <numop> <dur>
| <numprop> <numop> <num> | <numprop> <numop> <num>

@ -61,6 +61,8 @@ enum op {
EXPR_REGEXI, EXPR_REGEXI,
EXPR_PRUNE, EXPR_PRUNE,
EXPR_PRINT, EXPR_PRINT,
EXPR_REDIR_FILE,
EXPR_REDIR_PIPE,
EXPR_TYPE, EXPR_TYPE,
EXPR_ALLSET, EXPR_ALLSET,
EXPR_ANYSET, EXPR_ANYSET,
@ -143,6 +145,14 @@ struct thread {
struct mlist *cur; struct mlist *cur;
}; };
struct file {
enum op op;
const char *name;
const char *mode;
FILE *fp;
struct file *next;
};
static struct thread *thr; static struct thread *thr;
static char *argv0; static char *argv0;
@ -160,6 +170,8 @@ static char *pos;
static time_t now; static time_t now;
static int prune; static int prune;
static struct file *files, *fileq = NULL;
static void static void
ws() ws()
{ {
@ -179,6 +191,12 @@ token(char *token)
} }
} }
static int
peek(char *token)
{
return strncmp(pos, token, strlen(token)) == 0;
}
noreturn static void noreturn static void
parse_error(char *msg, ...) parse_error(char *msg, ...)
{ {
@ -642,14 +660,43 @@ parse_timecmp()
return 0; return 0;
} }
static struct expr *
parse_redir(struct expr *e)
{
char *s;
const char *m;
if (peek("||"))
return e;
if (token("|")) {
if (!parse_string(&s))
parse_error("expected command");
struct expr *r = mkexpr(EXPR_REDIR_PIPE);
r->a.string = s;
r->b.string = "w";
return chain(e, EXPR_AND, r);
}
else if (token(">>")) m = "a+";
else if (token(">")) m = "w+";
else return e;
if (!parse_string(&s))
parse_error("expected file name");
struct expr *r = mkexpr(EXPR_REDIR_FILE);
r->a.string = s;
r->b.string = m;
return chain(e, EXPR_AND, r);
}
static struct expr * static struct expr *
parse_and() parse_and()
{ {
struct expr *e1 = parse_timecmp(); struct expr *e1 = parse_redir(parse_timecmp());
struct expr *r = e1; struct expr *r = e1;
while (token("&&")) { while (token("&&")) {
struct expr *e2 = parse_timecmp(); struct expr *e2 = parse_redir(parse_timecmp());
r = chain(r, EXPR_AND, e2); r = chain(r, EXPR_AND, e2);
} }
@ -843,9 +890,48 @@ msg_addr(struct mailinfo *m, char *h, int t)
} }
} }
FILE *
redir(struct expr *e)
{
struct file *file;
FILE *fp;
for (file = files; file; file = file->next) {
if (e->op == file->op &&
strcmp(e->a.string, file->name) == 0 &&
strcmp(e->b.string, file->mode) == 0)
return file->fp;
}
fflush(stdout);
fp = NULL;
switch (e->op) {
case EXPR_REDIR_FILE: fp = fopen(e->a.string, e->b.string); break;
case EXPR_REDIR_PIPE: fp = popen(e->a.string, e->b.string); break;
}
if (!fp) {
fprintf(stderr, "%s: %s: %s\n", argv0, e->a.string, strerror(errno));
exit(3);
}
file = calloc(1, sizeof (struct file));
if (!file) {
perror("calloc");
exit(2);
}
file->op = e->op;
file->name = e->a.string;
file->mode = e->b.string;
file->fp = fp;
if (!files) files = file;
if (fileq) fileq->next = file;
fileq = file;
return fp;
}
int int
eval(struct expr *e, struct mailinfo *m) eval(struct expr *e, struct mailinfo *m)
{ {
FILE *fp;
switch (e->op) { switch (e->op) {
case EXPR_OR: case EXPR_OR:
return eval(e->a.expr, m) || eval(e->b.expr, m); return eval(e->a.expr, m) || eval(e->b.expr, m);
@ -859,6 +945,13 @@ eval(struct expr *e, struct mailinfo *m)
return 1; return 1;
case EXPR_PRINT: case EXPR_PRINT:
return 1; return 1;
case EXPR_REDIR_FILE:
case EXPR_REDIR_PIPE:
fp = redir(e);
fputs(m->fpath, fp);
putc('\n', fp);
fflush(fp);
return 1;
case EXPR_LT: case EXPR_LT:
case EXPR_LE: case EXPR_LE:
case EXPR_EQ: case EXPR_EQ:
@ -1040,10 +1133,10 @@ do_thr()
if (((Tflag && thr->matched) || ml->m->matched) && !ml->m->prune) { if (((Tflag && thr->matched) || ml->m->matched) && !ml->m->prune) {
int i; int i;
for (i = 0; i < ml->m->depth; i++) for (i = 0; i < ml->m->depth; i++)
putchar(' '); putc(' ', stdout);
fputs(ml->m->fpath, stdout); fputs(ml->m->fpath, stdout);
putchar('\n'); putc('\n', stdout);
kept++; kept++;
} }
@ -1126,7 +1219,8 @@ oneline(char *file)
goto out; goto out;
fputs(file, stdout); fputs(file, stdout);
putchar('\n'); putc('\n', stdout);
fflush(stdout);
kept++; kept++;
out: out:
@ -1174,5 +1268,15 @@ main(int argc, char *argv[])
if (vflag) if (vflag)
fprintf(stderr, "%ld mails tested, %ld picked.\n", i, kept); fprintf(stderr, "%ld mails tested, %ld picked.\n", i, kept);
for (; files; files = fileq) {
fileq = files->next;
if (files->op == EXPR_REDIR_PIPE)
pclose(files->fp);
else
fclose(files->fp);
free(files);
}
return 0; return 0;
} }

Loading…
Cancel
Save