static char * filter_gets _((SV *sv, PerlIO *fp, STRLEN append));
static void restore_rsfp _((void *f));
-static char too_long[] = "Identifier too long";
+static char ident_too_long[] = "Identifier too long";
static char *linestart; /* beg. of most recently read line */
{
char *oldbp = bufptr;
bool is_first = (oldbufptr == linestart);
- char *msg;
bufptr = s;
- New(890, msg, strlen(what) + 40, char);
- sprintf(msg, "%s found where operator expected", what);
- yywarn(msg);
- Safefree(msg);
+ yywarn(form("%s found where operator expected", what));
if (is_first)
warn("\t(Missing semicolon on previous line?)\n");
else if (oldoldbufptr && isIDFIRST(*oldoldbufptr)) {
return s;
if ((s = filter_gets(linestr, rsfp, (prevlen = SvCUR(linestr)))) == Nullch) {
if (minus_n || minus_p) {
- sv_setpv(linestr,minus_p ? ";}continue{print" : "");
+ sv_setpv(linestr,minus_p ?
+ ";}continue{print or die qq(-p destination: $!\\n)" :
+ "");
sv_catpv(linestr,";}");
minus_n = minus_p = 0;
}
PerlIO_clearerr(rsfp);
else
(void)PerlIO_close(rsfp);
+ if (e_fp == rsfp)
+ e_fp = Nullfp;
rsfp = Nullfp;
return s;
}
bufend = s + SvCUR(linestr);
s = bufptr;
incline(s);
- if (perldb && curstash != debstash) {
+ if (PERLDB_LINE && curstash != debstash) {
SV *sv = NEWSV(85,0);
sv_upgrade(sv, SVt_PVMG);
/* Force them to make up their mind on "@foo". */
if (pit == '@' && lex_state != LEX_NORMAL && !lex_brackets) {
GV *gv = gv_fetchpv(tokenbuf+1, FALSE, SVt_PVAV);
- if (!gv || ((tokenbuf[0] == '@') ? !GvAV(gv) : !GvHV(gv))) {
- char tmpbuf[1024];
- sprintf(tmpbuf, "In string, %s now must be written as \\%s",
- tokenbuf, tokenbuf);
- yyerror(tmpbuf);
- }
+ if (!gv || ((tokenbuf[0] == '@') ? !GvAV(gv) : !GvHV(gv)))
+ yyerror(form("In string, %s now must be written as \\%s",
+ tokenbuf, tokenbuf));
}
yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(tokenbuf+1, 0));
if (gv)
GvIMPORTED_AV_on(gv);
if (minus_F) {
- char *tmpbuf1;
- New(201, tmpbuf1, strlen(splitstr) * 2 + 20, char);
if (strchr("/'\"", *splitstr)
&& strchr(splitstr + 1, *splitstr))
- sprintf(tmpbuf1, "@F=split(%s);", splitstr);
+ sv_catpvf(linestr, "@F=split(%s);", splitstr);
else {
char delim;
s = "'~#\200\1'"; /* surely one char is unused...*/
while (s[1] && strchr(splitstr, *s)) s++;
delim = *s;
- sprintf(tmpbuf1, "@F=split(%s%c",
- "q" + (delim == '\''), delim);
- d = tmpbuf1 + strlen(tmpbuf1);
- for (s = splitstr; *s; ) {
+ sv_catpvf(linestr, "@F=split(%s%c",
+ "q" + (delim == '\''), delim);
+ for (s = splitstr; *s; s++) {
if (*s == '\\')
- *d++ = '\\';
- *d++ = *s++;
+ sv_catpvn(linestr, "\\", 1);
+ sv_catpvn(linestr, s, 1);
}
- sprintf(d, "%c);", delim);
+ sv_catpvf(linestr, "%c);", delim);
}
- sv_catpv(linestr,tmpbuf1);
- Safefree(tmpbuf1);
}
else
sv_catpv(linestr,"@F=split(' ');");
sv_catpv(linestr, "\n");
oldoldbufptr = oldbufptr = s = linestart = SvPVX(linestr);
bufend = SvPVX(linestr) + SvCUR(linestr);
- if (perldb && curstash != debstash) {
+ if (PERLDB_LINE && curstash != debstash) {
SV *sv = NEWSV(85,0);
sv_upgrade(sv, SVt_PVMG);
PerlIO_clearerr(rsfp);
else
(void)PerlIO_close(rsfp);
+ if (e_fp == rsfp)
+ e_fp = Nullfp;
rsfp = Nullfp;
}
if (!in_eval && (minus_n || minus_p)) {
incline(s);
} while (doextract);
oldoldbufptr = oldbufptr = bufptr = linestart = s;
- if (perldb && curstash != debstash) {
+ if (PERLDB_LINE && curstash != debstash) {
SV *sv = NEWSV(85,0);
sv_upgrade(sv, SVt_PVMG);
}
d = moreswitches(d);
} while (d);
- if (perldb && !oldpdb ||
+ if (PERLDB_LINE && !oldpdb ||
( minus_n || minus_p ) && !(oldn || oldp) )
/* if we have already added "LINE: while (<>) {",
we must not do it again */
oldoldbufptr = oldbufptr = s = linestart = SvPVX(linestr);
bufend = SvPVX(linestr) + SvCUR(linestr);
preambled = FALSE;
- if (perldb)
+ if (PERLDB_LINE)
(void)gv_fetchfile(origfilename);
goto retry;
}
s = skipspace(s);
if (*s == '}')
OPERATOR(HASHBRACK);
- if (isALPHA(*s)) {
- for (t = s; t < bufend && isALNUM(*t); t++) ;
+ /* This hack serves to disambiguate a pair of curlies
+ * as being a block or an anon hash. Normally, expectation
+ * determines that, but in cases where we're not in a
+ * position to expect anything in particular (like inside
+ * eval"") we have to resolve the ambiguity. This code
+ * covers the case where the first term in the curlies is a
+ * quoted string. Most other cases need to be explicitly
+ * disambiguated by prepending a `+' before the opening
+ * curly in order to force resolution as an anon hash.
+ *
+ * XXX should probably propagate the outer expectation
+ * into eval"" to rely less on this hack, but that could
+ * potentially break current behavior of eval"".
+ * GSAR 97-07-21
+ */
+ t = s;
+ if (*s == '\'' || *s == '"' || *s == '`') {
+ /* common case: get past first string, handling escapes */
+ for (t++; t < bufend && *t != *s;)
+ if (*t++ == '\\' && (*t == '\\' || *t == *s))
+ t++;
+ t++;
+ }
+ else if (*s == 'q') {
+ if (++t < bufend
+ && (!isALNUM(*t)
+ || ((*t == 'q' || *t == 'x') && ++t < bufend
+ && !isALNUM(*t)))) {
+ char *tmps;
+ char open, close, term;
+ I32 brackets = 1;
+
+ while (t < bufend && isSPACE(*t))
+ t++;
+ term = *t;
+ open = term;
+ if (term && (tmps = strchr("([{< )]}> )]}>",term)))
+ term = tmps[5];
+ close = term;
+ if (open == close)
+ for (t++; t < bufend; t++) {
+ if (*t == '\\' && t+1 < bufend && open != '\\')
+ t++;
+ else if (*t == open)
+ break;
+ }
+ else
+ for (t++; t < bufend; t++) {
+ if (*t == '\\' && t+1 < bufend)
+ t++;
+ else if (*t == close && --brackets <= 0)
+ break;
+ else if (*t == open)
+ brackets++;
+ }
+ }
+ t++;
}
- else if (*s == '\'' || *s == '"') {
- t = strchr(s+1,*s);
- if (!t++)
- t = s;
+ else if (isALPHA(*s)) {
+ for (t++; t < bufend && isALNUM(*t); t++) ;
}
- else
- t = s;
while (t < bufend && isSPACE(*t))
t++;
- if ((*t == ',' && !isLOWER(*s)) || (*t == '=' && t[1] == '>'))
+ /* if comma follows first term, call it an anon hash */
+ /* XXX it could be a comma expression with loop modifiers */
+ if (t < bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s)))
+ || (*t == '=' && t[1] == '>')))
OPERATOR(HASHBRACK);
if (expect == XREF)
expect = XTERM;
else if (isIDFIRST(*s)) {
char tmpbuf[sizeof tokenbuf];
scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
- if (keyword(tmpbuf, len))
- expect = XTERM; /* e.g. print $fh length() */
+ if (tmp = keyword(tmpbuf, len)) {
+ /* binary operators exclude handle interpretations */
+ switch (tmp) {
+ case -KEY_x:
+ case -KEY_eq:
+ case -KEY_ne:
+ case -KEY_gt:
+ case -KEY_lt:
+ case -KEY_ge:
+ case -KEY_le:
+ case -KEY_cmp:
+ break;
+ default:
+ expect = XTERM; /* e.g. print $fh length() */
+ break;
+ }
+ }
else {
GV *gv = gv_fetchpv(tmpbuf, FALSE, SVt_PVCV);
if (gv && GvCVu(gv))
/* Not a method, so call it a subroutine (if defined) */
if (gv && GvCVu(gv)) {
- CV* cv = GvCV(gv);
+ CV* cv;
if (lastchar == '-')
warn("Ambiguous use of -%s resolved as -&%s()",
tokenbuf, tokenbuf);
last_lop = oldbufptr;
last_lop_op = OP_ENTERSUB;
/* Check for a constant sub */
+ cv = GvCV(gv);
if ((sv = cv_const_sv(cv))) {
its_constant:
SvREFCNT_dec(((SVOP*)yylval.opval)->op_sv);
}
case KEY___FILE__:
+ yylval.opval = (OP*)newSVOP(OP_CONST, 0,
+ newSVsv(GvSV(curcop->cop_filegv)));
+ TERM(THING);
+
case KEY___LINE__:
- if (tokenbuf[2] == 'L')
- (void)sprintf(tokenbuf,"%ld",(long)curcop->cop_line);
- else
- strcpy(tokenbuf, SvPVX(GvSV(curcop->cop_filegv)));
- yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(tokenbuf,0));
+ yylval.opval = (OP*)newSVOP(OP_CONST, 0,
+ newSVpvf("%ld", (long)curcop->cop_line));
TERM(THING);
case KEY___PACKAGE__:
/*SUPPRESS 560*/
if (rsfp && (!in_eval || tokenbuf[2] == 'D')) {
- char dname[256];
char *pname = "main";
if (tokenbuf[2] == 'D')
pname = HvNAME(curstash ? curstash : defstash);
- sprintf(dname,"%s::DATA", pname);
- gv = gv_fetchpv(dname,TRUE, SVt_PVIO);
+ gv = gv_fetchpv(form("%s::DATA", pname), TRUE, SVt_PVIO);
GvMULTI_on(gv);
if (!GvIO(gv))
GvIOp(gv) = newIO();
}
if (*w)
for (; *w && isSPACE(*w); w++) ;
- if (!*w || !strchr(";|})]oa!=", *w)) /* an advisory hack only... */
+ if (!*w || !strchr(";|})]oaiuw!=", *w)) /* an advisory hack only... */
warn("%s (...) interpreted as function",name);
}
while (s < bufend && isSPACE(*s))
register char *e = d + destlen - 3; /* two-character token, ending NUL */
for (;;) {
if (d >= e)
- croak(too_long);
+ croak(ident_too_long);
if (isALNUM(*s))
*d++ = *s++;
else if (*s == '\'' && allow_package && isIDFIRST(s[1])) {
if (isDIGIT(*s)) {
while (isDIGIT(*s)) {
if (d >= e)
- croak(too_long);
+ croak(ident_too_long);
*d++ = *s++;
}
}
else {
for (;;) {
if (d >= e)
- croak(too_long);
+ croak(ident_too_long);
if (isALNUM(*s))
*d++ = *s++;
else if (*s == '\'' && isIDFIRST(s[1])) {
lex_state = LEX_INTERPEND;
if (funny == '#')
funny = '@';
- if (dowarn &&
+ if (dowarn && lex_state == LEX_NORMAL &&
(keyword(dest, d - dest) || perl_get_cv(dest, FALSE)))
warn("Ambiguous use of %c{%s} resolved to %c%s",
funny, dest, funny, dest);
*pmfl |= PMf_FOLD;
else if (ch == 'g')
*pmfl |= PMf_GLOBAL;
+ else if (ch == 'c')
+ *pmfl |= PMf_CONTINUE;
else if (ch == 'o')
*pmfl |= PMf_KEEP;
else if (ch == 'm')
pm = (PMOP*)newPMOP(OP_MATCH, 0);
if (multi_open == '?')
pm->op_pmflags |= PMf_ONCE;
- while (*s && strchr("iogmsx", *s))
+ while (*s && strchr("iogcmsx", *s))
pmflag(&pm->op_pmflags,*s++);
pm->op_pmpermflags = pm->op_pmflags;
multi_start = first_start; /* so whole substitution is taken together */
pm = (PMOP*)newPMOP(OP_SUBST, 0);
- while (*s && strchr("iogmsex", *s)) {
+ while (*s && strchr("iogcmsex", *s)) {
if (*s == 'e') {
s++;
es++;
SV *tmpstr;
char term;
register char *d;
+ register char *e;
char *peek;
int outer = (rsfp && !lex_inwhat);
s += 2;
d = tokenbuf;
+ e = tokenbuf + sizeof tokenbuf - 1;
if (!outer)
*d++ = '\n';
for (peek = s; *peek == ' ' || *peek == '\t'; peek++) ;
if (*peek && strchr("`'\"",*peek)) {
s = peek;
term = *s++;
- s = cpytill(d,s,bufend,term,&len);
+ s = delimcpy(d, e, s, bufend, term, &len);
+ d += len;
if (s < bufend)
s++;
- d += len;
}
else {
if (*s == '\\')
term = '"';
if (!isALNUM(*s))
deprecate("bare << to mean <<\"\"");
- while (isALNUM(*s))
- *d++ = *s++;
- } /* assuming tokenbuf won't clobber */
+ for (; isALNUM(*s); s++) {
+ if (d < e)
+ *d++ = *s;
+ }
+ }
+ if (d >= tokenbuf + sizeof tokenbuf - 1)
+ croak("Delimiter for here document is too long");
*d++ = '\n';
*d = '\0';
len = d - tokenbuf;
missingterm(tokenbuf);
}
curcop->cop_line++;
- if (perldb && curstash != debstash) {
+ if (PERLDB_LINE && curstash != debstash) {
SV *sv = NEWSV(88,0);
sv_upgrade(sv, SVt_PVMG);
{
register char *s = start;
register char *d;
+ register char *e;
I32 len;
d = tokenbuf;
- s = cpytill(d, s+1, bufend, '>', &len);
- if (s < bufend)
- s++;
- else
+ e = tokenbuf + sizeof tokenbuf;
+ s = delimcpy(d, e, s + 1, bufend, '>', &len);
+ if (len >= sizeof tokenbuf)
+ croak("Excessively long <> operator");
+ if (s >= bufend)
croak("Unterminated <> operator");
-
+ s++;
if (*d == '$' && d[1]) d++;
while (*d && (isALNUM(*d) || *d == '\'' || *d == ':'))
d++;
register char *to;
I32 brackets = 1;
- if (isSPACE(*s))
- s = skipspace(s);
+ if (isSPACE(*s)) {
+ /* "#" is allowed as delimiter if on same line */
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (isSPACE(*s))
+ s = skipspace(s);
+ }
CLINE;
term = *s;
multi_start = curcop->cop_line;
for (; s < bufend; s++,to++) {
if (*s == '\n' && !rsfp)
curcop->cop_line++;
- if (*s == '\\' && s+1 < bufend && term != '\\') {
- if (s[1] == term)
+ if (*s == '\\' && s+1 < bufend) {
+ if ((s[1] == multi_open) || (s[1] == multi_close))
s++;
else
*to++ = *s++;
}
- else if (*s == term && --brackets <= 0)
+ else if (*s == multi_close && --brackets <= 0)
break;
else if (*s == multi_open)
brackets++;
return Nullch;
}
curcop->cop_line++;
- if (perldb && curstash != debstash) {
+ if (PERLDB_LINE && curstash != debstash) {
SV *sv = NEWSV(88,0);
sv_upgrade(sv, SVt_PVMG);
{
register char *s = start;
register char *d;
+ register char *e;
I32 tryiv;
double value;
SV *sv;
I32 floatit;
char *lastub = 0;
+ static char number_too_long[] = "Number too long";
switch (*s) {
default:
case '6': case '7': case '8': case '9': case '.':
decimal:
d = tokenbuf;
+ e = tokenbuf + sizeof tokenbuf - 6; /* room for various punctuation */
floatit = FALSE;
while (isDIGIT(*s) || *s == '_') {
if (*s == '_') {
warn("Misplaced _ in number");
lastub = ++s;
}
- else
+ else {
+ if (d >= e)
+ croak(number_too_long);
*d++ = *s++;
+ }
}
if (dowarn && lastub && s - lastub != 3)
warn("Misplaced _ in number");
if (*s == '.' && s[1] != '.') {
floatit = TRUE;
*d++ = *s++;
- while (isDIGIT(*s) || *s == '_') {
- if (*s == '_')
- s++;
- else
- *d++ = *s++;
+ for (; isDIGIT(*s) || *s == '_'; s++) {
+ if (d >= e)
+ croak(number_too_long);
+ if (*s != '_')
+ *d++ = *s;
}
}
if (*s && strchr("eE",*s) && strchr("+-0123456789",s[1])) {
*d++ = 'e'; /* At least some Mach atof()s don't grok 'E' */
if (*s == '+' || *s == '-')
*d++ = *s++;
- while (isDIGIT(*s))
+ while (isDIGIT(*s)) {
+ if (d >= e)
+ croak(number_too_long);
*d++ = *s++;
+ }
}
*d = '\0';
sv = NEWSV(92,0);
yyerror(s)
char *s;
{
- char wbuf[40];
char *where = NULL;
char *context = NULL;
int contlen = -1;
+ SV *msg;
if (!yychar || (yychar == ';' && !rsfp))
where = "at EOF";
else
where = "within string";
}
- else if (yychar < 32)
- (void)sprintf(where = wbuf, "next char ^%c", toCTRL(yychar));
- else if (isPRINT_LC(yychar))
- (void)sprintf(where = wbuf, "next char %c", yychar);
- else
- (void)sprintf(where = wbuf, "next char \\%03o", yychar & 255);
- if (contlen == -1)
- contlen = strlen(where);
- (void)sprintf(buf, "%s at %s line %d, ",
- s, SvPVX(GvSV(curcop->cop_filegv)), curcop->cop_line);
+ else {
+ SV *where_sv = sv_2mortal(newSVpv("next char ", 0));
+ if (yychar < 32)
+ sv_catpvf(where_sv, "^%c", toCTRL(yychar));
+ else if (isPRINT_LC(yychar))
+ sv_catpvf(where_sv, "%c", yychar);
+ else
+ sv_catpvf(where_sv, "\\%03o", yychar & 255);
+ where = SvPVX(where_sv);
+ }
+ msg = sv_2mortal(newSVpv(s, 0));
+ sv_catpvf(msg, " at %_ line %ld, ",
+ GvSV(curcop->cop_filegv), (long)curcop->cop_line);
if (context)
- (void)sprintf(buf+strlen(buf), "near \"%.*s\"\n", contlen, context);
+ sv_catpvf(msg, "near \"%.*s\"\n", contlen, context);
else
- (void)sprintf(buf+strlen(buf), "%s\n", where);
+ sv_catpvf(msg, "%s\n", where);
if (multi_start < multi_end && (U32)(curcop->cop_line - multi_end) <= 1) {
- sprintf(buf+strlen(buf),
+ sv_catpvf(msg,
" (Might be a runaway multi-line %c%c string starting on line %ld)\n",
(int)multi_open,(int)multi_close,(long)multi_start);
multi_end = 0;
}
if (in_eval & 2)
- warn("%s",buf);
+ warn("%_", msg);
else if (in_eval)
- sv_catpv(GvSV(errgv),buf);
+ sv_catsv(GvSV(errgv), msg);
else
- PerlIO_printf(PerlIO_stderr(), "%s",buf);
+ PerlIO_write(PerlIO_stderr(), SvPVX(msg), SvCUR(msg));
if (++error_count >= 10)
- croak("%s has too many errors.\n",
- SvPVX(GvSV(curcop->cop_filegv)));
+ croak("%_ has too many errors.\n", GvSV(curcop->cop_filegv));
in_my = 0;
return 0;
}