aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c77
1 files changed, 43 insertions, 34 deletions
diff --git a/shell/ash.c b/shell/ash.c
index a31cee259..a63d40d7e 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1168,6 +1168,12 @@ struct strpush {
struct alias *ap; /* if push was associated with an alias */
#endif
char *string; /* remember the string since it may change */
+
+ /* Remember last two characters for pungetc. */
+ int lastc[2];
+
+ /* Number of outstanding calls to pungetc. */
+ int unget;
};
struct parsefile {
@@ -1180,6 +1186,12 @@ struct parsefile {
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
struct strpush basestrpush; /* so pushing one is fast */
+
+ /* Remember last two characters for pungetc. */
+ int lastc[2];
+
+ /* Number of outstanding calls to pungetc. */
+ int unget;
};
static struct parsefile basepf; /* top level input file */
@@ -9715,6 +9727,8 @@ pushstring(char *s, struct alias *ap)
g_parsefile->strpush = sp;
sp->prev_string = g_parsefile->next_to_pgetc;
sp->prev_left_in_line = g_parsefile->left_in_line;
+ sp->unget = g_parsefile->unget;
+ memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
#if ENABLE_ASH_ALIAS
sp->ap = ap;
if (ap) {
@@ -9724,6 +9738,7 @@ pushstring(char *s, struct alias *ap)
#endif
g_parsefile->next_to_pgetc = s;
g_parsefile->left_in_line = len;
+ g_parsefile->unget = 0;
INT_ON;
}
@@ -9751,6 +9766,8 @@ popstring(void)
#endif
g_parsefile->next_to_pgetc = sp->prev_string;
g_parsefile->left_in_line = sp->prev_left_in_line;
+ g_parsefile->unget = sp->unget;
+ memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
g_parsefile->strpush = sp->prev;
if (sp != &(g_parsefile->basestrpush))
free(sp);
@@ -9846,13 +9863,14 @@ preadfd(void)
*/
//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
#define pgetc_debug(...) ((void)0)
+static int pgetc(void);
static int
preadbuffer(void)
{
char *q;
int more;
- while (g_parsefile->strpush) {
+ if (g_parsefile->strpush) {
#if ENABLE_ASH_ALIAS
if (g_parsefile->left_in_line == -1
&& g_parsefile->strpush->ap
@@ -9864,13 +9882,7 @@ preadbuffer(void)
}
#endif
popstring();
- /* try "pgetc" now: */
- pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
- g_parsefile->left_in_line,
- g_parsefile->next_to_pgetc,
- g_parsefile->next_to_pgetc);
- if (--g_parsefile->left_in_line >= 0)
- return (unsigned char)(*g_parsefile->next_to_pgetc++);
+ return pgetc();
}
/* on both branches above g_parsefile->left_in_line < 0.
* "pgetc" needs refilling.
@@ -9949,27 +9961,28 @@ preadbuffer(void)
return (unsigned char)*g_parsefile->next_to_pgetc++;
}
-#define pgetc_as_macro() \
- (--g_parsefile->left_in_line >= 0 \
- ? (unsigned char)*g_parsefile->next_to_pgetc++ \
- : preadbuffer() \
- )
-
static int
pgetc(void)
{
- pgetc_debug("pgetc_fast at %d:%p'%s'",
+ int c;
+
+ pgetc_debug("pgetc at %d:%p'%s'",
g_parsefile->left_in_line,
g_parsefile->next_to_pgetc,
g_parsefile->next_to_pgetc);
- return pgetc_as_macro();
-}
+ if (g_parsefile->unget)
+ return g_parsefile->lastc[--g_parsefile->unget];
-#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
-# define pgetc_fast() pgetc()
-#else
-# define pgetc_fast() pgetc_as_macro()
-#endif
+ if (--g_parsefile->left_in_line >= 0)
+ c = (signed char)*g_parsefile->next_to_pgetc++;
+ else
+ c = preadbuffer();
+
+ g_parsefile->lastc[1] = g_parsefile->lastc[0];
+ g_parsefile->lastc[0] = c;
+
+ return c;
+}
#if ENABLE_ASH_ALIAS
static int
@@ -9977,11 +9990,11 @@ pgetc_without_PEOA(void)
{
int c;
do {
- pgetc_debug("pgetc_fast at %d:%p'%s'",
+ pgetc_debug("pgetc at %d:%p'%s'",
g_parsefile->left_in_line,
g_parsefile->next_to_pgetc,
g_parsefile->next_to_pgetc);
- c = pgetc_fast();
+ c = pgetc();
} while (c == PEOA);
return c;
}
@@ -10015,18 +10028,13 @@ pfgets(char *line, int len)
}
/*
- * Undo the last call to pgetc. Only one character may be pushed back.
+ * Undo a call to pgetc. Only two characters may be pushed back.
* PEOF may be pushed back.
*/
static void
pungetc(void)
{
- g_parsefile->left_in_line++;
- g_parsefile->next_to_pgetc--;
- pgetc_debug("pushed back to %d:%p'%s'",
- g_parsefile->left_in_line,
- g_parsefile->next_to_pgetc,
- g_parsefile->next_to_pgetc);
+ g_parsefile->unget++;
}
/*
@@ -10043,6 +10051,7 @@ pushfile(void)
pf->pf_fd = -1;
/*pf->strpush = NULL; - ckzalloc did it */
/*pf->basestrpush.prev = NULL;*/
+ /*pf->unget = 0;*/
g_parsefile = pf;
}
@@ -11451,7 +11460,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
IF_ASH_ALIAS(if (c != PEOA))
USTPUTC(c, out);
}
- c = pgetc_fast();
+ c = pgetc();
} /* for (;;) */
endword:
@@ -11945,7 +11954,7 @@ xxreadtoken(void)
setprompt_if(needprompt, 2);
startlinno = g_parsefile->linno;
for (;;) { /* until token or start of word found */
- c = pgetc_fast();
+ c = pgetc();
if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
continue;
@@ -12008,7 +12017,7 @@ xxreadtoken(void)
setprompt_if(needprompt, 2);
startlinno = g_parsefile->linno;
for (;;) { /* until token or start of word found */
- c = pgetc_fast();
+ c = pgetc();
switch (c) {
case ' ': case '\t':
IF_ASH_ALIAS(case PEOA:)