char * makestrspace(void) { int len = stackblocksize() - sstrnleft; growstackblock(); sstrnleft = stackblocksize() - len; return stackblock() + len; }
char * growstackstr(void) { int len = stackblocksize(); if (herefd >= 0 && len >= 1024) { xwrite(herefd, stackblock(), len); sstrnleft = len - 1; return stackblock(); } growstackblock(); sstrnleft = stackblocksize() - len - 1; return stackblock() + len; }
char * padvance(const char **path, const char *name) { const char *p, *start; char *q; int len; if (*path == NULL) return NULL; start = *path; for (p = start; *p && *p != ':' && *p != '%'; p++) ; /* nothing */ len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ while (stackblocksize() < len) growstackblock(); q = stackblock(); if (p != start) { memcpy(q, start, p - start); q += p - start; *q++ = '/'; } strcpy(q, name); pathopt = NULL; if (*p == '%') { pathopt = ++p; while (*p && *p != ':') p++; } if (*p == ':') *path = p + 1; else *path = NULL; return stalloc(len); }
char * growstackstr(void) { int len; len = stackblocksize(); return (growstrstackblock(len, 0)); }
STATIC int readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) { int c = firstc; char *out; int len; char line[EOFMARKLEN + 1]; struct nodelist *bqlist; int quotef; int dblquote; int varnest; /* levels of variables expansion */ int arinest; /* levels of arithmetic expansion */ int parenlevel; /* levels of parens in arithmetic */ int oldstyle; char const *prevsyntax; /* syntax before arithmetic */ int synentry; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &out; (void) "ef; (void) &dblquote; (void) &varnest; (void) &arinest; (void) &parenlevel; (void) &oldstyle; (void) &prevsyntax; (void) &syntax; (void) &synentry; #endif startlinno = plinno; dblquote = 0; if (syntax == DQSYNTAX) dblquote = 1; quotef = 0; bqlist = NULL; varnest = 0; arinest = 0; parenlevel = 0; STARTSTACKSTR(out); loop: { /* for each line, until end of word */ CHECKEND(); /* set c to PEOF if at end of here document */ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ synentry = syntax[c]; switch(synentry) { case CNL: /* '\n' */ if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(c, out); plinno++; if (doprompt) setprompt(2); else setprompt(0); c = pgetc(); goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); break; case CCTL: if (eofmark == NULL || dblquote) USTPUTC(CTLESC, out); USTPUTC(c, out); break; case CBACK: /* backslash */ c = pgetc(); if (c == PEOF) { USTPUTC('\\', out); pungetc(); } else if (c == '\n') { if (doprompt) setprompt(2); else setprompt(0); } else { if (dblquote && c != '\\' && c != '`' && c != '$' && (c != '"' || eofmark != NULL)) USTPUTC('\\', out); if (SQSYNTAX[c] == CCTL) USTPUTC(CTLESC, out); else if (eofmark == NULL) USTPUTC(CTLQUOTEMARK, out); USTPUTC(c, out); quotef++; } break; case CSQUOTE: if (eofmark == NULL) USTPUTC(CTLQUOTEMARK, out); syntax = SQSYNTAX; break; case CDQUOTE: if (eofmark == NULL) USTPUTC(CTLQUOTEMARK, out); syntax = DQSYNTAX; dblquote = 1; break; case CENDQUOTE: if (eofmark != NULL && arinest == 0 && varnest == 0) { USTPUTC(c, out); } else { if (arinest) { syntax = ARISYNTAX; dblquote = 0; } else if (eofmark == NULL) { syntax = BASESYNTAX; dblquote = 0; } quotef++; } break; case CVAR: /* '$' */ PARSESUB(); /* parse substitution */ break; case CENDVAR: /* '}' */ if (varnest > 0) { varnest--; USTPUTC(CTLENDVAR, out); } else { USTPUTC(c, out); } break; case CLP: /* '(' in arithmetic */ parenlevel++; USTPUTC(c, out); break; case CRP: /* ')' in arithmetic */ if (parenlevel > 0) { USTPUTC(c, out); --parenlevel; } else { if (pgetc() == ')') { if (--arinest == 0) { USTPUTC(CTLENDARI, out); syntax = prevsyntax; if (syntax == DQSYNTAX) dblquote = 1; else dblquote = 0; } else USTPUTC(')', out); } else { /* * unbalanced parens * (don't 2nd guess - no error) */ pungetc(); USTPUTC(')', out); } } break; case CBQUOTE: /* '`' */ PARSEBACKQOLD(); break; case CEOF: goto endword; /* exit outer loop */ default: if (varnest == 0) goto endword; /* exit outer loop */ USTPUTC(c, out); } c = pgetc_macro(); } } endword: if (syntax == ARISYNTAX) synerror("Missing '))'"); if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) synerror("Unterminated quoted string"); if (varnest != 0) { startlinno = plinno; synerror("Missing '}'"); } USTPUTC('\0', out); len = out - stackblock(); out = stackblock(); if (eofmark == NULL) { if ((c == '>' || c == '<') && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) { PARSEREDIR(); return lasttoken = TREDIR; } else { pungetc(); } } quoteflag = quotef; backquotelist = bqlist; grabstackblock(len); wordtext = out; return lasttoken = TWORD; /* end of readtoken routine */ /* * Check to see whether we are at the end of the here document. When this * is called, c is set to the first character of the next input line. If * we are at the end of the here document, this routine sets the c to PEOF. */ checkend: { if (eofmark) { if (striptabs) { while (c == '\t') c = pgetc(); } if (c == *eofmark) { if (pfgets(line, sizeof line) != NULL) { char *p, *q; p = line; for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); if (*p == '\n' && *q == '\0') { c = PEOF; plinno++; needprompt = doprompt; } else { pushstring(line, strlen(line), NULL); } } } } goto checkend_return; } /* * Parse a redirection operator. The variable "out" points to a string * specifying the fd to be redirected. The variable "c" contains the * first character of the redirection operator. */ parseredir: { char fd = *out; union node *np; np = (union node *)stalloc(sizeof (struct nfile)); if (c == '>') { np->nfile.fd = 1; c = pgetc(); if (c == '>') np->type = NAPPEND; else if (c == '&') np->type = NTOFD; else if (c == '|') np->type = NCLOBBER; else { np->type = NTO; pungetc(); } } else { /* c == '<' */ np->nfile.fd = 0; c = pgetc(); if (c == '<') { if (sizeof (struct nfile) != sizeof (struct nhere)) { np = (union node *)stalloc(sizeof (struct nhere)); np->nfile.fd = 0; } np->type = NHERE; heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); heredoc->here = np; if ((c = pgetc()) == '-') { heredoc->striptabs = 1; } else { heredoc->striptabs = 0; pungetc(); } } else if (c == '&') np->type = NFROMFD; else if (c == '>') np->type = NFROMTO; else { np->type = NFROM; pungetc(); } } if (fd != '\0') np->nfile.fd = digit_val(fd); redirnode = np; goto parseredir_return; } /* * Parse a substitution. At this point, we have read the dollar sign * and nothing else. */ parsesub: { int subtype; int typeloc; int flags; char *p; #ifndef GDB_HACK static const char types[] = "}-+?="; #endif int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ c = pgetc(); if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { USTPUTC('$', out); pungetc(); } else if (c == '(') { /* $(command) or $((arith)) */ if (pgetc() == '(') { PARSEARITH(); } else { pungetc(); PARSEBACKQNEW(); } } else { USTPUTC(CTLVAR, out); typeloc = out - stackblock(); USTPUTC(VSNORMAL, out); subtype = VSNORMAL; if (c == '{') { bracketed_name = 1; c = pgetc(); if (c == '#') { if ((c = pgetc()) == '}') c = '#'; else subtype = VSLENGTH; } else subtype = 0; } if (is_name(c)) { do { STPUTC(c, out); c = pgetc(); } while (is_in_name(c)); } else if (is_digit(c)) { if (bracketed_name) { do { STPUTC(c, out); c = pgetc(); } while (is_digit(c)); } else { STPUTC(c, out); c = pgetc(); } } else { if (! is_special(c)) badsub: synerror("Bad substitution"); USTPUTC(c, out); c = pgetc(); } STPUTC('=', out); flags = 0; if (subtype == 0) { switch (c) { case ':': flags = VSNUL; c = pgetc(); /*FALLTHROUGH*/ default: p = strchr(types, c); if (p == NULL) goto badsub; subtype = p - types + VSNORMAL; break; case '%': case '#': { int cc = c; subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; c = pgetc(); if (c == cc) subtype++; else pungetc(); break; } } } else { pungetc(); } if (subtype != VSLENGTH && (dblquote || arinest)) flags |= VSQUOTE; *(stackblock() + typeloc) = subtype | flags; if (subtype != VSNORMAL) varnest++; } goto parsesub_return; } /* * Called to parse command substitutions. Newstyle is set if the command * is enclosed inside $(...); nlpp is a pointer to the head of the linked * list of commands (passed by reference), and savelen is the number of * characters on the top of the stack which must be preserved. */ parsebackq: { struct nodelist **nlpp; int savepbq; union node *n; char *volatile str; struct jmploc jmploc; struct jmploc *volatile savehandler; int savelen; int saveprompt; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &saveprompt; #endif savepbq = parsebackquote; if (setjmp(jmploc.loc)) { if (str) ckfree(str); parsebackquote = 0; handler = savehandler; longjmp(handler->loc, 1); } INTOFF; str = NULL; savelen = out - stackblock(); if (savelen > 0) { str = ckmalloc(savelen); memcpy(str, stackblock(), savelen); } savehandler = handler; handler = &jmploc; INTON; if (oldstyle) { /* We must read until the closing backquote, giving special treatment to some slashes, and then push the string and reread it as input, interpreting it normally. */ char *out; int c; int savelen; char *str; STARTSTACKSTR(out); for (;;) { if (needprompt) { setprompt(2); needprompt = 0; } switch (c = pgetc()) { case '`': goto done; case '\\': if ((c = pgetc()) == '\n') { plinno++; if (doprompt) setprompt(2); else setprompt(0); /* * If eating a newline, avoid putting * the newline into the new character * stream (via the STPUTC after the * switch). */ continue; } if (c != '\\' && c != '`' && c != '$' && (!dblquote || c != '"')) STPUTC('\\', out); break; case '\n': plinno++; needprompt = doprompt; break; case PEOF: startlinno = plinno; synerror("EOF in backquote substitution"); break; default: break; } STPUTC(c, out); } done: STPUTC('\0', out); savelen = out - stackblock(); if (savelen > 0) { str = ckmalloc(savelen); memcpy(str, stackblock(), savelen); setinputstring(str, 1); } } nlpp = &bqlist; while (*nlpp) nlpp = &(*nlpp)->next; *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); (*nlpp)->next = NULL; parsebackquote = oldstyle; if (oldstyle) { saveprompt = doprompt; doprompt = 0; } n = list(0); if (oldstyle) doprompt = saveprompt; else { if (readtoken() != TRP) synexpect(TRP); } (*nlpp)->n = n; if (oldstyle) { /* * Start reading from old file again, ignoring any pushed back * tokens left from the backquote parsing */ popfile(); tokpushback = 0; } while (stackblocksize() <= savelen) growstackblock(); STARTSTACKSTR(out); if (str) { memcpy(out, str, savelen); STADJUST(savelen, out); INTOFF; ckfree(str); str = NULL; INTON; } parsebackquote = savepbq; handler = savehandler; if (arinest || dblquote) USTPUTC(CTLBACKQ | CTLQUOTE, out); else USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; else goto parsebackq_newreturn; } /* * Parse an arithmetic expansion (indicate start of one and set state) */ parsearith: { if (++arinest == 1) { prevsyntax = syntax; syntax = ARISYNTAX; USTPUTC(CTLARI, out); if (dblquote) USTPUTC('"',out); else USTPUTC(' ',out); } else { /* * we collapse embedded arithmetic expansion to * parenthesis, which should be equivalent */ USTPUTC('(', out); } goto parsearith_return; } } /* end of readtoken */