version 1.38, 2015/06/23 22:52:55 |
version 1.39, 2015/10/26 14:08:47 |
|
|
for (;;) { |
for (;;) { |
if ((p = cu_fgets(&lbuf, &bufsize)) == NULL) { |
if ((p = cu_fgets(&lbuf, &bufsize)) == NULL) { |
if (stack != 0) |
if (stack != 0) |
err(COMPILE, "unexpected EOF (pending }'s)"); |
error(COMPILE, "unexpected EOF (pending }'s)"); |
return (link); |
return (link); |
} |
} |
|
|
|
|
|
|
nonsel: /* Now parse the command */ |
nonsel: /* Now parse the command */ |
if (!*p) |
if (!*p) |
err(COMPILE, "command expected"); |
error(COMPILE, "command expected"); |
cmd->code = *p; |
cmd->code = *p; |
for (fp = cmd_fmts; fp->code; fp++) |
for (fp = cmd_fmts; fp->code; fp++) |
if (fp->code == *p) |
if (fp->code == *p) |
break; |
break; |
if (!fp->code) |
if (!fp->code) |
err(COMPILE, "invalid command code %c", *p); |
error(COMPILE, "invalid command code %c", *p); |
if (naddr > fp->naddr) |
if (naddr > fp->naddr) |
err(COMPILE, |
error(COMPILE, |
"command %c expects up to %d address(es), found %d", |
"command %c expects up to %d address(es), found %d", |
*p, fp->naddr, naddr); |
*p, fp->naddr, naddr); |
switch (fp->args) { |
switch (fp->args) { |
|
|
*/ |
*/ |
cmd->nonsel = 1; |
cmd->nonsel = 1; |
if (stack == 0) |
if (stack == 0) |
err(COMPILE, "unexpected }"); |
error(COMPILE, "unexpected }"); |
cmd2 = stack; |
cmd2 = stack; |
stack = cmd2->next; |
stack = cmd2->next; |
cmd2->next = cmd; |
cmd2->next = cmd; |
|
|
goto semicolon; |
goto semicolon; |
} |
} |
if (*p) |
if (*p) |
err(COMPILE, |
error(COMPILE, |
"extra characters at the end of %c command", cmd->code); |
"extra characters at the end of %c command", cmd->code); |
break; |
break; |
case TEXT: /* a c i */ |
case TEXT: /* a c i */ |
p++; |
p++; |
EATSPACE(); |
EATSPACE(); |
if (*p != '\\') |
if (*p != '\\') |
err(COMPILE, "command %c expects \\ followed by" |
error(COMPILE, "command %c expects \\ followed by" |
" text", cmd->code); |
" text", cmd->code); |
p++; |
p++; |
EATSPACE(); |
EATSPACE(); |
if (*p) |
if (*p) |
err(COMPILE, "extra characters after \\ at the" |
error(COMPILE, "extra characters after \\ at the" |
" end of %c command", cmd->code); |
" end of %c command", cmd->code); |
cmd->t = compile_text(); |
cmd->t = compile_text(); |
break; |
break; |
|
|
p++; |
p++; |
EATSPACE(); |
EATSPACE(); |
if (*p == '\0') |
if (*p == '\0') |
err(COMPILE, "filename expected"); |
error(COMPILE, "filename expected"); |
cmd->t = duptoeol(p, "w command", NULL); |
cmd->t = duptoeol(p, "w command", NULL); |
if (aflag) |
if (aflag) |
cmd->u.fd = -1; |
cmd->u.fd = -1; |
else if ((cmd->u.fd = open(p, |
else if ((cmd->u.fd = open(p, |
O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, |
O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, |
DEFFILEMODE)) == -1) |
DEFFILEMODE)) == -1) |
err(FATAL, "%s: %s", p, strerror(errno)); |
error(FATAL, "%s: %s", p, strerror(errno)); |
break; |
break; |
case RFILE: /* r */ |
case RFILE: /* r */ |
p++; |
p++; |
|
|
EATSPACE(); |
EATSPACE(); |
cmd->t = duptoeol(p, "label", &p); |
cmd->t = duptoeol(p, "label", &p); |
if (strlen(cmd->t) == 0) |
if (strlen(cmd->t) == 0) |
err(COMPILE, "empty label"); |
error(COMPILE, "empty label"); |
enterlabel(cmd); |
enterlabel(cmd); |
if (*p == ';') { |
if (*p == ';') { |
p++; |
p++; |
|
|
case SUBST: /* s */ |
case SUBST: /* s */ |
p++; |
p++; |
if (*p == '\0' || *p == '\\') |
if (*p == '\0' || *p == '\\') |
err(COMPILE, "substitute pattern can not be" |
error(COMPILE, "substitute pattern can not be" |
" delimited by newline or backslash"); |
" delimited by newline or backslash"); |
cmd->u.s = xmalloc(sizeof(struct s_subst)); |
cmd->u.s = xmalloc(sizeof(struct s_subst)); |
p = compile_re(p, &cmd->u.s->re); |
p = compile_re(p, &cmd->u.s->re); |
if (p == NULL) |
if (p == NULL) |
err(COMPILE, "unterminated substitute pattern"); |
error(COMPILE, "unterminated substitute pattern"); |
--p; |
--p; |
p = compile_subst(p, cmd->u.s); |
p = compile_subst(p, cmd->u.s); |
p = compile_flags(p, cmd->u.s); |
p = compile_flags(p, cmd->u.s); |
|
|
goto semicolon; |
goto semicolon; |
} |
} |
if (*p) |
if (*p) |
err(COMPILE, "extra text at the end of a" |
error(COMPILE, "extra text at the end of a" |
" transform command"); |
" transform command"); |
break; |
break; |
} |
} |
|
|
if (c == '\0') |
if (c == '\0') |
return (NULL); |
return (NULL); |
else if (c == '\\') |
else if (c == '\\') |
err(COMPILE, "\\ can not be used as a string delimiter"); |
error(COMPILE, "\\ can not be used as a string delimiter"); |
else if (c == '\n') |
else if (c == '\n') |
err(COMPILE, "newline can not be used as a string delimiter"); |
error(COMPILE, "newline can not be used as a string delimiter"); |
while (*p) { |
while (*p) { |
if (*p == '[' && *p != c) { |
if (*p == '[' && *p != c) { |
if ((d = compile_ccl(&p, d)) == NULL) |
if ((d = compile_ccl(&p, d)) == NULL) |
err(COMPILE, "unbalanced brackets ([])"); |
error(COMPILE, "unbalanced brackets ([])"); |
continue; |
continue; |
} else if (*p == '\\' && p[1] == '[') { |
} else if (*p == '\\' && p[1] == '[') { |
*d++ = *p++; |
*d++ = *p++; |
|
|
} |
} |
*repp = xmalloc(sizeof(regex_t)); |
*repp = xmalloc(sizeof(regex_t)); |
if (p && (eval = regcomp(*repp, re, Eflag ? REG_EXTENDED : 0)) != 0) |
if (p && (eval = regcomp(*repp, re, Eflag ? REG_EXTENDED : 0)) != 0) |
err(COMPILE, "RE error: %s", strregerror(eval, *repp)); |
error(COMPILE, "RE error: %s", strregerror(eval, *repp)); |
if (maxnsub < (*repp)->re_nsub) |
if (maxnsub < (*repp)->re_nsub) |
maxnsub = (*repp)->re_nsub; |
maxnsub = (*repp)->re_nsub; |
free(re); |
free(re); |
|
|
ref = *p - '0'; |
ref = *p - '0'; |
if (s->re != NULL && |
if (s->re != NULL && |
ref > s->re->re_nsub) |
ref > s->re->re_nsub) |
err(COMPILE, |
error(COMPILE, |
"\\%c not defined in the RE", *p); |
"\\%c not defined in the RE", *p); |
if (s->maxbref < ref) |
if (s->maxbref < ref) |
s->maxbref = ref; |
s->maxbref = ref; |
|
|
s->new = xrealloc(text, size); |
s->new = xrealloc(text, size); |
return (p); |
return (p); |
} else if (*p == '\n') { |
} else if (*p == '\n') { |
err(COMPILE, |
error(COMPILE, |
"unescaped newline inside substitute pattern"); |
"unescaped newline inside substitute pattern"); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
} |
} |
size += sp - op; |
size += sp - op; |
} while ((p = cu_fgets(&lbuf, &bufsize))); |
} while ((p = cu_fgets(&lbuf, &bufsize))); |
err(COMPILE, "unterminated substitute in regular expression"); |
error(COMPILE, "unterminated substitute in regular expression"); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
|
|
switch (*p) { |
switch (*p) { |
case 'g': |
case 'g': |
if (gn) |
if (gn) |
err(COMPILE, "more than one number or 'g' in" |
error(COMPILE, "more than one number or 'g' in" |
" substitute flags"); |
" substitute flags"); |
gn = 1; |
gn = 1; |
s->n = 0; |
s->n = 0; |
|
|
case '4': case '5': case '6': |
case '4': case '5': case '6': |
case '7': case '8': case '9': |
case '7': case '8': case '9': |
if (gn) |
if (gn) |
err(COMPILE, "more than one number or 'g' in" |
error(COMPILE, "more than one number or 'g' in" |
" substitute flags"); |
" substitute flags"); |
gn = 1; |
gn = 1; |
l = strtol(p, &p, 10); |
l = strtol(p, &p, 10); |
if (l <= 0 || l >= INT_MAX) |
if (l <= 0 || l >= INT_MAX) |
err(COMPILE, |
error(COMPILE, |
"number in substitute flags out of range"); |
"number in substitute flags out of range"); |
s->n = (int)l; |
s->n = (int)l; |
continue; |
continue; |
|
|
p++; |
p++; |
#ifdef HISTORIC_PRACTICE |
#ifdef HISTORIC_PRACTICE |
if (*p != ' ') { |
if (*p != ' ') { |
err(WARNING, "space missing before w wfile"); |
error(WARNING, "space missing before w wfile"); |
return (p); |
return (p); |
} |
} |
#endif |
#endif |
|
|
if (*p == '\n') |
if (*p == '\n') |
break; |
break; |
if (q >= eq) |
if (q >= eq) |
err(COMPILE, "wfile too long"); |
error(COMPILE, "wfile too long"); |
*q++ = *p++; |
*q++ = *p++; |
} |
} |
*q = '\0'; |
*q = '\0'; |
if (q == wfile) |
if (q == wfile) |
err(COMPILE, "no wfile specified"); |
error(COMPILE, "no wfile specified"); |
s->wfile = strdup(wfile); |
s->wfile = strdup(wfile); |
if (!aflag && (s->wfd = open(wfile, |
if (!aflag && (s->wfd = open(wfile, |
O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, |
O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, |
DEFFILEMODE)) == -1) |
DEFFILEMODE)) == -1) |
err(FATAL, "%s: %s", wfile, strerror(errno)); |
error(FATAL, "%s: %s", wfile, strerror(errno)); |
return (p); |
return (p); |
default: |
default: |
err(COMPILE, |
error(COMPILE, |
"bad flag in substitute command: '%c'", *p); |
"bad flag in substitute command: '%c'", *p); |
break; |
break; |
} |
} |
|
|
char *old = NULL, *new = NULL; |
char *old = NULL, *new = NULL; |
|
|
if (*p == '\0' || *p == '\\') |
if (*p == '\0' || *p == '\\') |
err(COMPILE, |
error(COMPILE, |
"transform pattern can not be delimited by newline or backslash"); |
"transform pattern can not be delimited by newline or backslash"); |
old = xmalloc(strlen(p) + 1); |
old = xmalloc(strlen(p) + 1); |
p = compile_delimited(p, old, 1); |
p = compile_delimited(p, old, 1); |
if (p == NULL) { |
if (p == NULL) { |
err(COMPILE, "unterminated transform source string"); |
error(COMPILE, "unterminated transform source string"); |
goto bad; |
goto bad; |
} |
} |
new = xmalloc(strlen(p) + 1); |
new = xmalloc(strlen(p) + 1); |
p = compile_delimited(--p, new, 1); |
p = compile_delimited(--p, new, 1); |
if (p == NULL) { |
if (p == NULL) { |
err(COMPILE, "unterminated transform target string"); |
error(COMPILE, "unterminated transform target string"); |
goto bad; |
goto bad; |
} |
} |
EATSPACE(); |
EATSPACE(); |
if (strlen(new) != strlen(old)) { |
if (strlen(new) != strlen(old)) { |
err(COMPILE, "transform strings are not the same length"); |
error(COMPILE, "transform strings are not the same length"); |
goto bad; |
goto bad; |
} |
} |
/* We assume characters are 8 bits */ |
/* We assume characters are 8 bits */ |
|
|
case '/': /* Context address */ |
case '/': /* Context address */ |
p = compile_re(p, &a->u.r); |
p = compile_re(p, &a->u.r); |
if (p == NULL) |
if (p == NULL) |
err(COMPILE, "unterminated regular expression"); |
error(COMPILE, "unterminated regular expression"); |
a->type = AT_RE; |
a->type = AT_RE; |
return (p); |
return (p); |
|
|
|
|
a->u.l = strtoul(p, &end, 10); |
a->u.l = strtoul(p, &end, 10); |
return (end); |
return (end); |
default: |
default: |
err(COMPILE, "expected context address"); |
error(COMPILE, "expected context address"); |
return (NULL); |
return (NULL); |
} |
} |
} |
} |
|
|
*s = '\0'; |
*s = '\0'; |
} |
} |
if (ws) |
if (ws) |
err(WARNING, "whitespace after %s", ctype); |
error(WARNING, "whitespace after %s", ctype); |
len = s - start + 1; |
len = s - start + 1; |
if (semi) |
if (semi) |
*semi = s; |
*semi = s; |
|
|
break; |
break; |
} |
} |
if ((cp->u.c = findlabel(cp->t)) == NULL) |
if ((cp->u.c = findlabel(cp->t)) == NULL) |
err(COMPILE2, "undefined label '%s'", cp->t); |
error(COMPILE2, "undefined label '%s'", cp->t); |
free(cp->t); |
free(cp->t); |
break; |
break; |
case '{': |
case '{': |
|
|
lhp = &labels[h & LHMASK]; |
lhp = &labels[h & LHMASK]; |
for (lh = *lhp; lh != NULL; lh = lh->lh_next) |
for (lh = *lhp; lh != NULL; lh = lh->lh_next) |
if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0) |
if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0) |
err(COMPILE2, "duplicate label '%s'", cp->t); |
error(COMPILE2, "duplicate label '%s'", cp->t); |
lh = xmalloc(sizeof *lh); |
lh = xmalloc(sizeof *lh); |
lh->lh_next = *lhp; |
lh->lh_next = *lhp; |
lh->lh_hash = h; |
lh->lh_hash = h; |
|
|
for (lh = labels[i]; lh != NULL; lh = next) { |
for (lh = labels[i]; lh != NULL; lh = next) { |
next = lh->lh_next; |
next = lh->lh_next; |
if (!lh->lh_ref) |
if (!lh->lh_ref) |
err(WARNING, "unused label '%s'", |
error(WARNING, "unused label '%s'", |
lh->lh_cmd->t); |
lh->lh_cmd->t); |
free(lh); |
free(lh); |
} |
} |