2016-08-01 12:55:34 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2016-08-01 15:18:05 +00:00
|
|
|
#include <regex.h>
|
2016-08-01 12:55:34 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "blaze822.h"
|
|
|
|
|
|
|
|
static char *expr;
|
|
|
|
|
|
|
|
char *
|
|
|
|
subst(char *str, char *srch, char *repl, char *flags)
|
|
|
|
{
|
|
|
|
static char buf[4096];
|
|
|
|
char *bufe = buf + sizeof buf;
|
|
|
|
|
|
|
|
int iflag = !!strchr(flags, 'i');
|
|
|
|
int gflag = !!strchr(flags, 'g');
|
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
#define APP(o, l) do { if (bufe-b < (ssize_t)l) return str; memcpy(b, str+i+o, l); b += l; } while (0)
|
|
|
|
#define APPC(c) do { if (b >= bufe) return str; *b++ = c; } while (0)
|
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
regex_t srchrx;
|
|
|
|
regmatch_t pmatch[10];
|
|
|
|
if (regcomp(&srchrx, srch, iflag ? REG_ICASE : 0) != 0)
|
|
|
|
return str;
|
|
|
|
|
|
|
|
char *b = buf;
|
|
|
|
|
|
|
|
regoff_t i = 0;
|
|
|
|
while (1) {
|
|
|
|
if (regexec(&srchrx, str+i, 9, pmatch, 0) != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
APP(0, pmatch[0].rm_so);
|
|
|
|
|
|
|
|
char *t = repl;
|
|
|
|
while (*t) {
|
|
|
|
// & == \0
|
|
|
|
if (*t == '&' || (*t == '\\' && isdigit(*(t+1)))) {
|
|
|
|
int n;
|
|
|
|
if (*t == '&') {
|
|
|
|
t++;
|
|
|
|
n = 0;
|
|
|
|
} else {
|
|
|
|
t++;
|
|
|
|
n = *t++ - '0';
|
|
|
|
}
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
APP(pmatch[n].rm_so,
|
|
|
|
pmatch[n].rm_eo - pmatch[n].rm_so);
|
|
|
|
} else if (*t == '\\' && *(t+1)) {
|
|
|
|
t++;
|
|
|
|
APPC(*t++);
|
|
|
|
} else {
|
|
|
|
APPC(*t++);
|
|
|
|
}
|
|
|
|
}
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
i += pmatch[0].rm_eo; // advance to end of match
|
|
|
|
if (!gflag)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0) { // any match?
|
|
|
|
APP(0, strlen(str + i));
|
|
|
|
*b = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
printhdr(char *hdr, int rest)
|
|
|
|
{
|
2017-01-26 19:27:26 +00:00
|
|
|
int uc = 1;
|
2016-08-01 12:55:34 +00:00
|
|
|
|
2017-01-26 19:27:26 +00:00
|
|
|
while (*hdr && *hdr != ':') {
|
|
|
|
putc(uc ? toupper(*hdr) : *hdr, stdout);
|
|
|
|
uc = (*hdr == '-');
|
|
|
|
hdr++;
|
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
|
2017-01-26 19:27:26 +00:00
|
|
|
if (rest) {
|
|
|
|
printf("%s\n", hdr);
|
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sed(char *file)
|
|
|
|
{
|
|
|
|
struct message *msg = blaze822_file(file);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char *h = 0;
|
2017-01-26 19:27:26 +00:00
|
|
|
while ((h = blaze822_next_header(msg, h))) {
|
2016-08-01 12:55:34 +00:00
|
|
|
regex_t headerrx;
|
|
|
|
char headersel[1024];
|
|
|
|
|
|
|
|
char *v = strchr(h, ':');
|
|
|
|
if (!v)
|
|
|
|
continue;
|
|
|
|
v++;
|
|
|
|
while (*v && (*v == ' ' || *v == '\t'))
|
|
|
|
v++;
|
|
|
|
|
|
|
|
v = strdup(v);
|
|
|
|
|
|
|
|
char *e = expr;
|
|
|
|
while (*e) {
|
|
|
|
while (*e &&
|
|
|
|
(*e == ' ' || *e == '\t' || *e == '\n' || *e == ';'))
|
|
|
|
e++;
|
|
|
|
|
|
|
|
*headersel = 0;
|
|
|
|
if (*e == '/') {
|
|
|
|
e++;
|
|
|
|
char *s = e;
|
|
|
|
// parse_headers, sets headersel
|
|
|
|
while (*e && *e != '/')
|
|
|
|
e++;
|
|
|
|
snprintf(headersel, sizeof headersel,
|
2016-08-08 12:03:29 +00:00
|
|
|
"^(%.*s)*:", (int)(e-s), s);
|
2016-08-01 12:55:34 +00:00
|
|
|
for (s = headersel; *s && *(s+1); s++)
|
|
|
|
if (*s == ':')
|
|
|
|
*s = '|';
|
2017-02-24 14:09:06 +00:00
|
|
|
int rv;
|
|
|
|
if ((rv = regcomp(&headerrx, headersel, REG_EXTENDED)) != 0) {
|
|
|
|
char buf[100];
|
|
|
|
regerror(rv, &headerrx, buf, sizeof buf);
|
|
|
|
fprintf(stderr, "msed: %s\n", buf);
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
if (*e)
|
|
|
|
e++;
|
|
|
|
}
|
|
|
|
|
|
|
|
char sep;
|
|
|
|
char *s;
|
|
|
|
if (!*headersel || regexec(&headerrx, h, 0, 0, 0) == 0) {
|
|
|
|
switch (*e) {
|
|
|
|
case 'd':
|
|
|
|
free(v);
|
|
|
|
v = 0;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
// skipped here;
|
2016-08-01 15:18:05 +00:00
|
|
|
e++;
|
|
|
|
if ((*e == ' ' || *e == ';' || *e == '\n' || !*e)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sep = *e;
|
2016-08-01 12:55:34 +00:00
|
|
|
if (!sep) {
|
2017-02-24 14:10:56 +00:00
|
|
|
fprintf(stderr, "msed: unterminated a command\n");
|
2016-08-01 12:55:34 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
while (*e && *e != sep)
|
|
|
|
e++;
|
|
|
|
if (!(*e == ' ' || *e == ';' || *e == '\n' || !*e)) {
|
2017-02-24 14:10:56 +00:00
|
|
|
fprintf(stderr, "msed: unterminated a command\n");
|
2016-08-01 12:55:34 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2016-08-01 15:18:05 +00:00
|
|
|
break;
|
2016-08-01 12:55:34 +00:00
|
|
|
case 'c':
|
|
|
|
sep = *++e;
|
|
|
|
s = ++e;
|
|
|
|
while (*e && *e != sep)
|
|
|
|
e++;
|
|
|
|
free(v);
|
|
|
|
v = strndup(s, e-s);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
sep = *++e;
|
|
|
|
s = ++e;
|
|
|
|
while (*e && *e != sep)
|
|
|
|
e++;
|
|
|
|
char *t = ++e;
|
|
|
|
while (*e && *e != sep)
|
|
|
|
e++;
|
|
|
|
char *u = ++e;
|
|
|
|
while (*e == 'i' || *e == 'g')
|
|
|
|
e++;
|
|
|
|
|
|
|
|
if (!(*e == ' ' || *e == ';' || *e == '\n' || !*e)) {
|
2017-02-24 14:10:56 +00:00
|
|
|
fprintf(stderr, "msed: unterminated s command\n");
|
2016-08-01 12:55:34 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX stack allocate
|
|
|
|
char *from = strndup(s, t-s-1);
|
|
|
|
char *to = strndup(t, u-t-1);
|
|
|
|
char *flags = strndup(u, e-u);
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
char *ov = v;
|
|
|
|
v = strdup(subst(ov, from, to, flags));
|
|
|
|
free(ov);
|
|
|
|
|
|
|
|
free(from);
|
|
|
|
free(to);
|
|
|
|
free(flags);
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
2017-02-24 14:10:56 +00:00
|
|
|
fprintf(stderr, "msed: unknown command: '%c'\n", *e);
|
2016-08-01 12:55:34 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2016-08-01 15:18:05 +00:00
|
|
|
while (*e && *e != ';' && *e != '\n')
|
2016-08-01 12:55:34 +00:00
|
|
|
e++;
|
|
|
|
}
|
|
|
|
if (v) {
|
|
|
|
printhdr(h, 0);
|
|
|
|
printf(": %s\n", v);
|
|
|
|
free(v);
|
|
|
|
}
|
2017-01-26 19:27:26 +00:00
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
|
|
|
|
// loop, do all a//
|
|
|
|
|
|
|
|
char *hs, *he;
|
|
|
|
char *e = expr;
|
|
|
|
while (*e) {
|
|
|
|
while (*e &&
|
|
|
|
(*e == ' ' || *e == '\t' || *e == '\n' || *e == ';'))
|
|
|
|
e++;
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
hs = he = 0;
|
|
|
|
if (*e == '/') {
|
|
|
|
e++;
|
|
|
|
hs = e;
|
|
|
|
// parse_headers, sets headersel
|
|
|
|
while (*e && *e != '/')
|
|
|
|
e++;
|
|
|
|
he = e;
|
|
|
|
if (*e)
|
|
|
|
e++;
|
|
|
|
}
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
char sep;
|
|
|
|
char *s;
|
2016-08-01 15:18:05 +00:00
|
|
|
char *h = 0;
|
|
|
|
char *v = 0;
|
2016-08-01 12:55:34 +00:00
|
|
|
switch (*e) {
|
2017-08-31 15:30:17 +00:00
|
|
|
case 'a':
|
|
|
|
if (he != hs) {
|
|
|
|
h = strndup(hs, he-hs);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "msed: used command a without header name\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
e++;
|
|
|
|
if (*e == ' ' || *e == '\t' || *e == '\n' || *e == ';' || !*e) {
|
|
|
|
fprintf(stderr, "msed: no header value for %s\n", h);
|
|
|
|
exit(1);
|
|
|
|
} else {
|
|
|
|
sep = *e;
|
|
|
|
if (!sep) {
|
|
|
|
fprintf(stderr, "msed: unterminated a command\n");
|
2016-08-08 12:03:29 +00:00
|
|
|
exit(1);
|
2016-08-01 12:55:34 +00:00
|
|
|
}
|
2017-08-31 15:30:17 +00:00
|
|
|
s = ++e;
|
|
|
|
while (*e && *e != sep)
|
|
|
|
e++;
|
|
|
|
v = strndup(s, e-s);
|
|
|
|
}
|
2016-08-01 15:18:05 +00:00
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
if (blaze822_chdr(msg, h))
|
|
|
|
break;
|
2016-08-01 15:18:05 +00:00
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
printhdr(h, 0);
|
|
|
|
printf(": %s\n", v);
|
2016-08-01 15:18:05 +00:00
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
break;
|
2016-08-01 12:55:34 +00:00
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
case 'c':
|
|
|
|
case 'd':
|
|
|
|
case 's':
|
|
|
|
// ignore here;
|
|
|
|
break;
|
2016-08-01 12:55:34 +00:00
|
|
|
}
|
2016-08-01 15:18:05 +00:00
|
|
|
while (*e && *e != ';' && *e != '\n')
|
2016-08-01 12:55:34 +00:00
|
|
|
e++;
|
2017-01-26 19:27:26 +00:00
|
|
|
}
|
2016-08-01 12:55:34 +00:00
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
fwrite(blaze822_body(msg), 1, blaze822_bodylen(msg), stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
while ((c = getopt(argc, argv, "")) != -1)
|
2017-08-31 15:30:17 +00:00
|
|
|
switch (c) {
|
2016-08-01 12:55:34 +00:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "Usage: msed [expr] [msgs...]\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr = argv[optind];
|
|
|
|
optind++;
|
|
|
|
|
|
|
|
if (argc == optind && isatty(0))
|
|
|
|
blaze822_loop1(".", sed);
|
|
|
|
else
|
|
|
|
blaze822_loop(argc-optind, argv+optind, sed);
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-08-01 12:55:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|