sh.lex.c revision 70a587dd392ff1dbaa2875c6c33921f08ea85273
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h> /* for lseek prototype */
#include "sh.h"
#include "sh.tconst.h"
/*
* C shell
*/
/*
* These lexical routines read input and form lists of words.
* There is some involved processing here, because of the complications
* of input buffering, and especially because of history substitution.
*/
void getdol(void);
int readc(bool);
/*
* Peekc is a peek characer for getC, peekread for readc.
* There is a subtlety here in many places... history routines
* will read ahead and then insert stuff into the input stream.
* If they push back a character then they must push it behind
* the text substituted by the history substitution. On the other
* hand in several places we need 2 peek characters. To make this
* all work, the history routines read with getC, and make use both
* of ungetC and unreadc. The key observation is that the state
* of getC at the call of a history reference is such that calls
* to getC from the history routines will always yield calls of
* readc, unless this peeking is involved. That is to say that during
* getexcl the variables lap, exclp, and exclnxt are all zero.
*
* Getdol invokes history substitution, hence the extra peek, peekd,
* which it can ungetD to be before history substitutions.
*/
int exclc; /* Count of remainig words in ! subst */
/*
* Lex returns to its caller not only a wordlist (as a "var" parameter)
* but also whether a history substitution occurred. This is used in
* the main (process) routine to determine whether to echo, and also
* when called by the alias routine to determine whether to keep the
* argument list.
*/
bool hadhist;
bool
{
int c;
#ifdef TRACE
tprintf("TRACE- lex()\n");
#endif
do
c = readc(0);
while (issp(c));
/* make sure history is enabled */
/* ^lef^rit from tty is short !:s^lef^rit */
getexcl(c);
else
unreadc(c);
/*
* The following loop is written so that the links needed
* by freelex will be ready and rarin to go even if it is
* interrupted.
*/
do {
#ifdef TRACE
tprintf("Exiting lex()\n");
#endif
return (hadhist);
}
void
{
#ifdef TRACE
tprintf("TRACE- prlex()\n");
#endif
for (;;) {
break;
Putchar(' ');
}
}
void
{
#ifdef TRACE
tprintf("TRACE- copylex()\n");
#endif
do {
}
void
{
#ifdef TRACE
tprintf("TRACE- freelex()\n");
#endif
}
}
tchar *
word(void)
{
bool dolflg;
int i;
#ifdef TRACE
tprintf("TRACE- word()\n");
#endif
i = BUFSIZ - 4;
loop:
;
switch (c) {
case '&':
case '|':
case '<':
case '>':
*wp++ = c;
if (c1 == c)
else
goto ret;
case '#':
if (intty)
break;
c = 0;
do {
c1 = c;
c = getC(0);
} while (c != '\n');
if (c1 == '\\')
goto loop;
/* fall into ... */
case ';':
case '(':
case ')':
case '\n':
*wp++ = c;
goto ret;
case '\\':
c = getC(0);
if (c == '\n') {
if (onelflg == 1)
onelflg = 2;
goto loop;
}
if (c != HIST)
*wp++ = '\\', --i;
c |= QUOTE;
}
c1 = 0;
for (;;) {
if (c1) {
if (c == c1) {
c1 = 0;
} else if (c == '\\') {
c = getC(0);
if (c == HIST)
c |= QUOTE;
else {
if (c == '\n')
#if 0
if (c1 == '`')
c = ' ';
else
#endif
c |= QUOTE;
ungetC(c);
c = '\\';
}
} else if (c == '\n') {
ungetC(c);
break;
}
if (c == '\\') {
c = getC(0);
if (c == '\n') {
if (onelflg == 1)
onelflg = 2;
break;
}
if (c != HIST)
*wp++ = '\\', --i;
c |= QUOTE;
c1 = c;
} else if (c != '#' || !intty) {
ungetC(c);
break;
}
}
if (--i > 0) {
*wp++ = c;
} else {
seterr("Word too long");
break;
}
}
ret:
*wp = 0;
#ifdef TRACE
#endif
}
{
tchar c;
top:
if (c = peekc) {
peekc = 0;
return (c);
}
if (lap) {
if ((c = *lap++) == 0)
lap = 0;
else {
/*
* don't quote things if there was an error (err!=0)
* the input is original, not from a substitution and
* therefore should not be quoted
*/
c |= QUOTE;
return (c);
}
}
if (c = peekd) {
peekd = 0;
return (c);
}
if (exclp) {
if (c = *exclp++)
return (c);
return (' ');
}
exclp = 0;
exclnxt = 0;
}
if (exclnxt) {
if (--exclc < 0)
exclnxt = 0;
else
goto top;
}
c = readc(0);
getdol();
goto top;
}
getexcl(0);
goto top;
}
return (c);
}
void
getdol(void)
{
int c;
int sc;
bool special = 0;
#ifdef TRACE
tprintf("TRACE- getdol()\n");
#endif
if (isspnl(c)) {
ungetD(c);
return;
}
if (c == '{')
if (c == '#' || c == '?')
*np++ = c;
switch (c) {
case '<':
case '$':
case '*':
if (special)
goto vsyn;
goto ret;
case '\n':
ungetD(c);
np--;
goto vsyn;
default:
p = np;
if (digit(c)) {
/* make sure the variable names are MAX_VAR_LEN chars or less */
*np++ = c;
}
} else if (letter(c)) {
(np - p) < MAX_VAR_LEN) {
*np++ = c;
}
}
else
goto vsyn;
if ((np - p) > MAX_VAR_LEN)
{
seterr("Variable name too long");
goto ret;
}
}
if (c == '[') {
*np++ = c;
do {
if (c == '\n') {
ungetD(c);
np--;
goto vsyn;
}
/* need to leave space for possible modifiers */
{
seterr("Variable reference too long");
goto ret;
}
*np++ = c;
} while (c != ']');
}
if (c == ':') {
if (c == 'g')
*np++ = c;
goto vsyn;
} else
ungetD(c);
if (sc == '{') {
if (c != '}') {
ungetC(c);
goto vsyn;
}
*np++ = c;
}
ret:
*np = 0;
return;
vsyn:
seterr("Variable syntax");
goto ret;
}
void
{
int len = 0;
#ifdef TRACE
tprintf("TRACE- addla()\n");
#endif
if (lap) {
}
/* len+5 is allow 4 additional charecters just to be safe */
if (lap) {
}
}
int quesarg;
void
{
int c;
#ifdef TRACE
tprintf("TRACE- getexcl()\n");
#endif
if (sc == 0) {
if (sc != '{') {
sc = 0;
}
}
quesarg = -1;
if (hp == 0)
return;
hadhist = 1;
dol = 0;
dol++;
else
dol++;
goto subst;
}
c = getC(0);
/* if (!any(c, ":^$*-%")) */ /* change needed for char -> tchar */
if (! (c == ':' || c == '^' || c == '$' || c == '*' ||
c == '-' || c == '%'))
goto subst;
if (c == ':') {
c = getC(0);
unreadc(c);
if (letter(c) || c == '&') {
c = ':';
goto subst;
}
} else
ungetC(c);
return;
c = getC(0);
if (c == '*')
ungetC(c), c = '-';
if (c == '-') {
return;
c = getC(0);
}
while (--left >= 0)
do {
c = getC(0);
} while (c == ':');
}
unreadc(c);
if (sc == '{') {
c = getC(0);
if (c != '}')
seterr("Bad ! form");
}
}
struct wordent *
{
int delim;
int c;
int sc;
bool global = 0;
#ifdef TRACE
tprintf("TRACE- getsub()\n");
#endif
exclnxt = 0;
if (c == 'g')
switch (c) {
case 'p':
justpr++;
goto ret;
case 'x':
case 'q':
global++;
/* fall into ... */
case 'h':
case 'r':
case 't':
case 'e':
break;
case '&':
if (slhs[0] == 0) {
seterr("No prev sub");
goto ret;
}
break;
#if 0
case '~':
if (lhsb[0] == 0)
goto badlhs;
break;
#endif
case 's':
bads:
lhsb[0] = 0;
seterr("Bad substitute");
goto ret;
}
for (;;) {
c = getC(0);
if (c == '\n') {
unreadc(c);
break;
}
if (c == delim)
break;
goto bads;
if (c == '\\') {
c = getC(0);
if (c != delim && c != '\\')
*cp++ = '\\';
}
*cp++ = c;
}
*cp++ = 0;
else if (lhsb[0] == 0) {
/* badlhs: */
seterr("No prev lhs");
goto ret;
}
for (;;) {
c = getC(0);
if (c == '\n') {
unreadc(c);
break;
}
if (c == delim)
break;
#if 0
if (c == '~') {
goto toorhs;
continue;
}
#endif
/* toorhs: */
seterr("Rhs too long");
goto ret;
}
if (c == '\\') {
c = getC(0);
if (c != delim /* && c != '~' */)
*cp++ = '\\';
}
*cp++ = c;
}
*cp++ = 0;
break;
default:
if (c == '\n')
unreadc(c);
goto ret;
}
if (exclc)
ret:
return (en);
}
struct wordent *
{
bool didsub = 0;
int i = exclc;
#ifdef TRACE
tprintf("TRACE- dosub()\n");
#endif
while (--i >= 0) {
}
if (didsub == 0)
seterr("Modifier failed");
}
tchar *
{
int i;
#ifdef TRACE
tprintf("TRACE- subword()\n");
#endif
switch (type) {
case 'r':
case 'e':
case 'h':
case 't':
case 'q':
case 'x':
if (wp == 0)
*adid = 1;
return (wp);
default:
i = BUFSIZ - 4;
case '\\':
np++;
/* fall into ... */
default:
if (--i < 0)
goto ovflo;
continue;
case '&':
if (i < 0)
goto ovflo;
*wp = 0;
continue;
}
if (i < 0) {
seterr("Subst buf ovflo");
return (S_ /* "" */);
}
*wp = 0;
*adid = 1;
}
}
}
tchar *
{
int c;
#ifdef TRACE
tprintf("TRACE- domod()\n");
#endif
switch (type) {
case 'x':
case 'q':
return (wp);
case 'h':
case 't':
while (*--wp != '/')
continue;
if (type == 'h')
else
return (xp);
case 'e':
case 'r':
if (*wp == '.') {
if (type == 'e')
else
return (xp);
}
}
return (0);
}
int
{
#ifdef TRACE
tprintf("TRACE- matchs()\n");
#endif
return (*pat == 0);
}
int
{
int c = getC(0);
int i;
#ifdef TRACE
tprintf("TRACE- getsel()\n");
#endif
switch (c) {
case '%':
if (quesarg == -1)
goto bad;
if (*al < 0)
break;
case '-':
if (*al < 0) {
*al = 0;
unreadc(c);
}
return (1);
case '^':
if (*al < 0)
*al = 1;
*ar = 1;
break;
case '$':
if (*al < 0)
break;
case '*':
if (*al < 0)
*al = 1;
*ar = 0;
*al = 1;
return (1);
}
break;
default:
if (digit(c)) {
i = 0;
while (digit(c)) {
i = i * 10 + c - '0';
c = getC(0);
}
if (i < 0)
i = dol + 1;
if (*al < 0)
*al = i;
*ar = i;
} else
if (*al < 0)
else
unreadc(c);
break;
}
if (first) {
c = getC(0);
unreadc(c);
/* if (any(c, "-$*")) */ /* char -> tchar */
if (c == '-' || c == '$' || c == '*')
return (1);
}
bad:
seterr("Bad ! arg selector");
return (0);
}
return (1);
}
struct wordent *
{
int c;
int event;
bool back = 0;
#ifdef TRACE
tprintf("TRACE- gethent()\n");
#endif
if (c == HIST) {
if (alhistp)
return (alhistp);
goto skip;
}
switch (c) {
case ':':
case '^':
case '$':
case '*':
case '%':
ungetC(c);
return (alhistp);
break;
case '-':
back = 1;
c = getC(0);
goto number;
case '#': /* !# is command being typed in (mrh) */
return (¶ml);
default:
/* if (any(c, "(=~")) { */
if (c == '(' || c == '=' || c == '~') {
unreadc(c);
return (0);
}
if (digit(c))
goto number;
/* while (!any(c, ": \t\\\n}")) { */
*np++ = c;
c = getC(0);
}
unreadc(c);
return (0);
}
*np++ = 0;
if (hp)
case '?':
for (;;) {
c = getC(0);
if (c == '\n') {
unreadc(c);
break;
}
if (c == '?')
break;
*np++ = c;
}
if (lhsb[0] == 0) {
seterr("No prev search");
return (0);
}
} else
*np++ = 0;
if (hp)
event = 0;
while (digit(c)) {
c = getC(0);
}
if (back)
unreadc(c);
break;
}
skip:
}
return (0);
}
struct Hist *
{
#ifdef TRACE
tprintf("TRACE- findev()\n");
#endif
tchar *p, *q;
int argno = 0;
continue;
if (!anyarg) {
p = cp;
do
if (!*p)
return (hp);
while (*p++ == *q++);
continue;
}
do {
p = cp;
q = dp;
do
if (!*p) {
return (hp);
}
while (*p++ == *q++);
}
argno++;
}
return (0);
}
void
{
#ifdef TRACE
tprintf("TRACE- noev()\n");
#endif
}
void
{
#ifdef TRACE
tprintf("TRACE- setexclp()\n");
#endif
return;
}
void
{
peekread = c;
}
int
{
int c;
static int sincereal;
if (c = peekread) {
peekread = 0;
return (c);
}
top:
if (alvecp) {
if (c = *alvecp++)
return (c);
if (*alvec) {
return (' ');
}
}
if (alvec) {
alvec++;
goto top;
}
/* Infinite source! */
return ('\n');
}
if (evalp) {
if (c = *evalp++)
return (c);
if (*evalvec) {
return (' ');
}
evalp = 0;
}
if (evalvec) {
doneinp = 1;
reset();
}
evalvec++;
goto top;
}
return ('\n');
}
do {
if (wanteof)
return (-1);
exitstat();
}
if (arginp) {
if ((c = *arginp++) == 0) {
return ('\n');
}
return (c);
}
c = bgetc();
if (c < 0) {
if (wanteof)
return (-1);
/* was isatty but raw with ignoreeof yields problems */
/* was 'short' for FILEC */
int ctpgrp;
if (++sincereal > 25)
goto oops;
if (tpgrp != -1 &&
(char *)&tpgrp);
goto reread;
}
if (loginsh)
printf("\nUse \"logout\" to logout.\n");
else
printf("\nUse \"exit\" to leave csh.\n");
reset();
}
if (chkstop == 0) {
panystop(1);
}
}
oops:
doneinp = 1;
reset();
}
sincereal = 0;
if (c == '\n' && onelflg)
onelflg--;
} while (c == 0);
return (c);
}
static void
expand_fbuf(void)
{
if (fbuf) {
}
sizeof (tchar));
fblocks++;
}
int
bgetc(void)
{
#ifdef FILEC
int roomleft;
#endif
#ifdef TELL
if (cantell) {
}
do
if (c <= 0)
return (-1);
feobp += c;
}
fseekp++;
return (c);
}
#endif
expand_fbuf();
goto again;
}
#ifndef FILEC
for (;;) {
#else
for (;;) {
if (c > roomleft) {
expand_fbuf();
} else if (c > 0) {
c * sizeof (tchar));
}
} else {
if (c > roomleft) {
expand_fbuf();
}
}
#endif
if (c >= 0)
break;
if (errno == EWOULDBLOCK) {
int off = 0;
break;
}
if (c <= 0)
return (-1);
feobp += c;
#ifndef FILEC
goto again;
#else
goto again;
#endif
}
fseekp++;
return (c);
}
void
bfree(void)
{
int sb, i;
#ifdef TELL
if (cantell)
return;
#endif
if (whyles)
return;
if (sb > 0) {
for (i = 0; i < sb; i++)
}
}
void
{
fseekp = l;
#ifdef TELL
if (!cantell) {
#endif
if (!whyles)
return;
continue;
#ifdef TELL
}
#endif
}
/* any similarity to bell telephone is purely accidental */
#ifndef btell
btell(void)
{
return (fseekp);
}
#endif
void
btoeof(void)
{
wfree();
bfree();
}
#ifdef TELL
void
settell(void)
{
cantell = 0;
return;
return;
fblocks = 1;
cantell = 1;
}
#endif