📄 parseaddr.c
字号:
{
usrerr("653 Unbalanced '\"'");
c = '"';
}
else if (cmntcnt > 0)
{
usrerr("653 Unbalanced '('");
c = ')';
}
else if (anglecnt > 0)
{
c = '>';
usrerr("653 Unbalanced '<'");
}
else
break;
p--;
}
else if (c == delim && cmntcnt <= 0 && state != QST)
{
if (anglecnt <= 0)
break;
/* special case for better error management */
if (delim == ',' && !route_syntax)
{
usrerr("653 Unbalanced '<'");
c = '>';
p--;
}
}
if (tTd(22, 101))
dprintf("c=%c, s=%d; ", c, state);
/* chew up special characters */
*q = '\0';
if (bslashmode)
{
bslashmode = FALSE;
/* kludge \! for naive users */
if (cmntcnt > 0)
{
c = NOCHAR;
continue;
}
else if (c != '!' || state == QST)
{
*q++ = '\\';
continue;
}
}
if (c == '\\')
{
bslashmode = TRUE;
}
else if (state == QST)
{
/* EMPTY */
/* do nothing, just avoid next clauses */
}
else if (c == '(' && toktab['('] == SPC)
{
cmntcnt++;
c = NOCHAR;
}
else if (c == ')' && toktab['('] == SPC)
{
if (cmntcnt <= 0)
{
usrerr("653 Unbalanced ')'");
c = NOCHAR;
}
else
cmntcnt--;
}
else if (cmntcnt > 0)
{
c = NOCHAR;
}
else if (c == '<')
{
char *ptr = p;
anglecnt++;
while (isascii(*ptr) && isspace(*ptr))
ptr++;
if (*ptr == '@')
route_syntax = TRUE;
}
else if (c == '>')
{
if (anglecnt <= 0)
{
usrerr("653 Unbalanced '>'");
c = NOCHAR;
}
else
anglecnt--;
route_syntax = FALSE;
}
else if (delim == ' ' && isascii(c) && isspace(c))
c = ' ';
if (c == NOCHAR)
continue;
/* see if this is end of input */
if (c == delim && anglecnt <= 0 && state != QST)
break;
newstate = StateTab[state][toktab[c & 0xff]];
if (tTd(22, 101))
dprintf("ns=%02o\n", newstate);
state = newstate & TYPE;
if (state == ILL)
{
if (isascii(c) && isprint(c))
usrerr("653 Illegal character %c", c);
else
usrerr("653 Illegal character 0x%02x", c);
}
if (bitset(M, newstate))
c = NOCHAR;
if (bitset(B, newstate))
break;
}
/* new token */
if (tok != q)
{
*q++ = '\0';
if (tTd(22, 36))
{
dprintf("tok=");
xputs(tok);
dprintf("\n");
}
if (avp >= &av[MAXATOM])
{
usrerr("553 5.1.0 prescan: too many tokens");
goto returnnull;
}
if (q - tok > MAXNAME)
{
usrerr("553 5.1.0 prescan: token too long");
goto returnnull;
}
*avp++ = tok;
}
} while (c != '\0' && (c != delim || anglecnt > 0));
*avp = NULL;
p--;
if (delimptr != NULL)
*delimptr = p;
if (tTd(22, 12))
{
dprintf("prescan==>");
printav(av);
}
CurEnv->e_to = saveto;
if (av[0] == NULL)
{
if (tTd(22, 1))
dprintf("prescan: null leading token\n");
return NULL;
}
return av;
}
/*
** REWRITE -- apply rewrite rules to token vector.
**
** This routine is an ordered production system. Each rewrite
** rule has a LHS (called the pattern) and a RHS (called the
** rewrite); 'rwr' points the the current rewrite rule.
**
** For each rewrite rule, 'avp' points the address vector we
** are trying to match against, and 'pvp' points to the pattern.
** If pvp points to a special match value (MATCHZANY, MATCHANY,
** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
** matched is saved away in the match vector (pointed to by 'mvp').
**
** When a match between avp & pvp does not match, we try to
** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
** we must also back out the match in mvp. If we reach a
** MATCHANY or MATCHZANY we just extend the match and start
** over again.
**
** When we finally match, we rewrite the address vector
** and try over again.
**
** Parameters:
** pvp -- pointer to token vector.
** ruleset -- the ruleset to use for rewriting.
** reclevel -- recursion level (to catch loops).
** e -- the current envelope.
**
** Returns:
** A status code. If EX_TEMPFAIL, higher level code should
** attempt recovery.
**
** Side Effects:
** pvp is modified.
*/
struct match
{
char **match_first; /* first token matched */
char **match_last; /* last token matched */
char **match_pattern; /* pointer to pattern */
};
#define MAXMATCH 9 /* max params per rewrite */
int
rewrite(pvp, ruleset, reclevel, e)
char **pvp;
int ruleset;
int reclevel;
register ENVELOPE *e;
{
register char *ap; /* address pointer */
register char *rp; /* rewrite pointer */
register char *rulename; /* ruleset name */
register char *prefix;
register char **avp; /* address vector pointer */
register char **rvp; /* rewrite vector pointer */
register struct match *mlp; /* cur ptr into mlist */
register struct rewrite *rwr; /* pointer to current rewrite rule */
int ruleno; /* current rule number */
int rstat = EX_OK; /* return status */
int loopcount;
struct match mlist[MAXMATCH]; /* stores match on LHS */
char *npvp[MAXATOM + 1]; /* temporary space for rebuild */
char buf[MAXLINE];
char name[6];
if (ruleset < 0 || ruleset >= MAXRWSETS)
{
syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset);
return EX_CONFIG;
}
rulename = RuleSetNames[ruleset];
if (rulename == NULL)
{
snprintf(name, sizeof name, "%d", ruleset);
rulename = name;
}
if (OpMode == MD_TEST)
prefix = "";
else
prefix = "rewrite: ruleset ";
if (OpMode == MD_TEST)
{
printf("%s%-16.16s input:", prefix, rulename);
printav(pvp);
}
else if (tTd(21, 1))
{
dprintf("%s%-16.16s input:", prefix, rulename);
printav(pvp);
}
if (reclevel++ > MaxRuleRecursion)
{
syserr("rewrite: excessive recursion (max %d), ruleset %s",
MaxRuleRecursion, rulename);
return EX_CONFIG;
}
if (pvp == NULL)
return EX_USAGE;
/*
** Run through the list of rewrite rules, applying
** any that match.
*/
ruleno = 1;
loopcount = 0;
for (rwr = RewriteRules[ruleset]; rwr != NULL; )
{
int status;
/* if already canonical, quit now */
if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
break;
if (tTd(21, 12))
{
if (tTd(21, 15))
dprintf("-----trying rule (line %d):",
rwr->r_line);
else
dprintf("-----trying rule:");
printav(rwr->r_lhs);
}
/* try to match on this rule */
mlp = mlist;
rvp = rwr->r_lhs;
avp = pvp;
if (++loopcount > 100)
{
syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
rulename, ruleno);
if (tTd(21, 1))
{
dprintf("workspace: ");
printav(pvp);
}
break;
}
while ((ap = *avp) != NULL || *rvp != NULL)
{
rp = *rvp;
if (tTd(21, 35))
{
dprintf("ADVANCE rp=");
xputs(rp);
dprintf(", ap=");
xputs(ap);
dprintf("\n");
}
if (rp == NULL)
{
/* end-of-pattern before end-of-address */
goto backup;
}
if (ap == NULL && (*rp & 0377) != MATCHZANY &&
(*rp & 0377) != MATCHZERO)
{
/* end-of-input with patterns left */
goto backup;
}
switch (*rp & 0377)
{
case MATCHCLASS:
/* match any phrase in a class */
mlp->match_pattern = rvp;
mlp->match_first = avp;
extendclass:
ap = *avp;
if (ap == NULL)
goto backup;
mlp->match_last = avp++;
cataddr(mlp->match_first, mlp->match_last,
buf, sizeof buf, '\0');
if (!wordinclass(buf, rp[1]))
{
if (tTd(21, 36))
{
dprintf("EXTEND rp=");
xputs(rp);
dprintf(", ap=");
xputs(ap);
dprintf("\n");
}
goto extendclass;
}
if (tTd(21, 36))
dprintf("CLMATCH\n");
mlp++;
break;
case MATCHNCLASS:
/* match any token not in a class */
if (wordinclass(ap, rp[1]))
goto backup;
/* FALLTHROUGH */
case MATCHONE:
case MATCHANY:
/* match exactly one token */
mlp->match_pattern = rvp;
mlp->match_first = avp;
mlp->match_last = avp++;
mlp++;
break;
case MATCHZANY:
/* match zero or more tokens */
mlp->match_pattern = rvp;
mlp->match_first = avp;
mlp->match_last = avp - 1;
mlp++;
break;
case MATCHZERO:
/* match zero tokens */
break;
case MACRODEXPAND:
/*
** Match against run-time macro.
** This algorithm is broken for the
** general case (no recursive macros,
** improper tokenization) but should
** work for the usual cases.
*/
ap = macvalue(rp[1], e);
mlp->match_first = avp;
if (tTd(21, 2))
dprintf("rewrite: LHS $&%s => \"%s\"\n",
macname(rp[1]),
ap == NULL ? "(NULL)" : ap);
if (ap == NULL)
break;
while (*ap != '\0')
{
if (*avp == NULL ||
strncasecmp(ap, *avp, strlen(*avp)) != 0)
{
/* no match */
avp = mlp->match_first;
goto backup;
}
ap += strlen(*avp++);
}
/* match */
break;
default:
/* must have exact match */
if (sm_strcasecmp(rp, ap))
goto backup;
avp++;
break;
}
/* successful match on this token */
rvp++;
continue;
backup:
/* match failed -- back up */
while (--mlp >= mlist)
{
rvp = mlp->match_pattern;
rp = *rvp;
avp = mlp->match_last + 1;
ap = *avp;
if (tTd(21, 36))
{
dprintf("BACKUP rp=");
xputs(rp);
dprintf(", ap=");
xputs(ap);
dprintf("\n");
}
if (ap == NULL)
{
/* run off the end -- back up again */
continue;
}
if ((*rp & 0377) == MATCHANY ||
(*rp & 0377) == MATCHZANY)
{
/* extend binding and continue */
mlp->match_last = avp++;
rvp++;
mlp++;
break;
}
if ((*rp & 0377) == MATCHCLASS)
{
/* extend binding and try again */
mlp->match_last = avp;
goto extendclass;
}
}
if (mlp < mlist)
{
/* total failure to match */
break;
}
}
/*
** See if we successfully matched
*/
if (mlp < mlist || *rvp != NULL)
{
if (tTd(21, 10))
dprintf("----- rule fails\n");
rwr = rwr->r_next;
ruleno++;
loopcount = 0;
continue;
}
rvp = rwr->r_rhs;
if (tTd(21, 12))
{
dprintf("-----rule matches:");
printav(rvp);
}
rp = *rvp;
if (rp != NULL)
{
if ((*rp & 0377) == CANONUSER)
{
rvp++;
rwr = rwr->r_next;
ruleno++;
loopcount = 0;
}
else if ((*rp & 0377) == CANONHOST)
{
rvp++;
rwr = NULL;
}
}
/* substitute */
for (avp = npvp; *rvp != NULL; rvp++)
{
register struct match *m;
register char **pp;
rp = *rvp;
if ((*rp & 0377) == MATCHREPL)
{
/* substitute from LHS */
m = &mlist[rp[1] - '1'];
if (m < mlist || m >= mlp)
{
syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
rulename, rp[1]);
return EX_CONFIG;
}
if (tTd(21, 15))
{
dprintf("$%c:", rp[1]);
pp = m->match_first;
while (pp <= m->match_last)
{
dprintf(" %lx=\"",
(u_long) *pp);
(void) dflush();
dprintf("%s\"", *pp++);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -