Magellan Linux

Diff of /trunk/mkinitrd-magellan/klibc/usr/dash/parser.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1121 by niro, Fri Apr 24 18:32:46 2009 UTC revision 1122 by niro, Wed Aug 18 21:11:40 2010 UTC
# Line 32  Line 32 
32   * SUCH DAMAGE.   * SUCH DAMAGE.
33   */   */
34    
35    #if HAVE_ALLOCA_H
36  #include <alloca.h>  #include <alloca.h>
37    #endif
38    
39  #include <stdlib.h>  #include <stdlib.h>
40    
41  #include "shell.h"  #include "shell.h"
# Line 51  Line 54 
54  #include "alias.h"  #include "alias.h"
55  #include "show.h"  #include "show.h"
56  #include "builtins.h"  #include "builtins.h"
57    #include "system.h"
58  #ifndef SMALL  #ifndef SMALL
59  #include "myhistedit.h"  #include "myhistedit.h"
60  #endif  #endif
# Line 59  Line 63 
63   * Shell command parser.   * Shell command parser.
64   */   */
65    
 #define EOFMARKLEN 79  
   
66  /* values returned by readtoken */  /* values returned by readtoken */
67  #include "token.h"  #include "token.h"
68    
69    
70    
71    /* Used by expandstr to get here-doc like behaviour. */
72    #define FAKEEOFMARK (char *)1
73    
74    
75    
76  struct heredoc {  struct heredoc {
77   struct heredoc *next; /* next here document in list */   struct heredoc *next; /* next here document in list */
78   union node *here; /* redirection node */   union node *here; /* redirection node */
# Line 101  STATIC int peektoken(void); Line 108  STATIC int peektoken(void);
108  STATIC int readtoken(void);  STATIC int readtoken(void);
109  STATIC int xxreadtoken(void);  STATIC int xxreadtoken(void);
110  STATIC int readtoken1(int, char const *, char *, int);  STATIC int readtoken1(int, char const *, char *, int);
 STATIC int noexpand(char *);  
111  STATIC void synexpect(int) __attribute__((__noreturn__));  STATIC void synexpect(int) __attribute__((__noreturn__));
112  STATIC void synerror(const char *) __attribute__((__noreturn__));  STATIC void synerror(const char *) __attribute__((__noreturn__));
113  STATIC void setprompt(int);  STATIC void setprompt(int);
# Line 116  isassignment(const char *p) Line 122  isassignment(const char *p)
122   return *q == '=';   return *q == '=';
123  }  }
124    
125    static inline int realeofmark(const char *eofmark)
126    {
127     return eofmark && eofmark != FAKEEOFMARK;
128    }
129    
130    
131  /*  /*
132   * Read and parse a command.  Returns NEOF on end of file.  (NULL is a   * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
# Line 346  TRACE(("expecting DO got %s %s\n", tokna Line 357  TRACE(("expecting DO got %s %s\n", tokna
357   n1 = (union node *)stalloc(sizeof (struct nfor));   n1 = (union node *)stalloc(sizeof (struct nfor));
358   n1->type = NFOR;   n1->type = NFOR;
359   n1->nfor.var = wordtext;   n1->nfor.var = wordtext;
360   checkkwd = CHKKWD | CHKALIAS;   checkkwd = CHKNL | CHKKWD | CHKALIAS;
361   if (readtoken() == TIN) {   if (readtoken() == TIN) {
362   app = &ap;   app = &ap;
363   while (readtoken() == TWORD) {   while (readtoken() == TWORD) {
# Line 372  TRACE(("expecting DO got %s %s\n", tokna Line 383  TRACE(("expecting DO got %s %s\n", tokna
383   * Newline or semicolon here is optional (but note   * Newline or semicolon here is optional (but note
384   * that the original Bourne shell only allowed NL).   * that the original Bourne shell only allowed NL).
385   */   */
386   if (lasttoken != TNL && lasttoken != TSEMI)   if (lasttoken != TSEMI)
387   tokpushback++;   tokpushback++;
388   }   }
389   checkkwd = CHKNL | CHKKWD | CHKALIAS;   checkkwd = CHKNL | CHKKWD | CHKALIAS;
# Line 391  TRACE(("expecting DO got %s %s\n", tokna Line 402  TRACE(("expecting DO got %s %s\n", tokna
402   n2->narg.text = wordtext;   n2->narg.text = wordtext;
403   n2->narg.backquote = backquotelist;   n2->narg.backquote = backquotelist;
404   n2->narg.next = NULL;   n2->narg.next = NULL;
405   do {   checkkwd = CHKNL | CHKKWD | CHKALIAS;
406   checkkwd = CHKKWD | CHKALIAS;   if (readtoken() != TIN)
  } while (readtoken() == TNL);  
  if (lasttoken != TIN)  
407   synexpect(TIN);   synexpect(TIN);
408   cpp = &n1->ncase.cases;   cpp = &n1->ncase.cases;
409  next_case:  next_case:
# Line 596  parsefname(void) Line 605  parsefname(void)
605  {  {
606   union node *n = redirnode;   union node *n = redirnode;
607    
608     if (n->type == NHERE)
609     checkkwd = CHKEOFMARK;
610   if (readtoken() != TWORD)   if (readtoken() != TWORD)
611   synexpect(-1);   synexpect(-1);
612   if (n->type == NHERE) {   if (n->type == NHERE) {
613   struct heredoc *here = heredoc;   struct heredoc *here = heredoc;
614   struct heredoc *p;   struct heredoc *p;
  int i;  
615    
616   if (quoteflag == 0)   if (quoteflag == 0)
617   n->type = NXHERE;   n->type = NXHERE;
618   TRACE(("Here document %d\n", n->type));   TRACE(("Here document %d\n", n->type));
  if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)  
  synerror("Illegal eof marker for << redirection");  
619   rmescapes(wordtext);   rmescapes(wordtext);
620   here->eofmark = wordtext;   here->eofmark = wordtext;
621   here->next = NULL;   here->next = NULL;
# Line 768  xxreadtoken(void) Line 776  xxreadtoken(void)
776   continue;   continue;
777   case '\\':   case '\\':
778   if (pgetc() == '\n') {   if (pgetc() == '\n') {
779   startlinno = ++plinno;   startlinno = lineno_inc();
780   if (doprompt)   if (doprompt)
781   setprompt(2);   setprompt(2);
782   continue;   continue;
# Line 776  xxreadtoken(void) Line 784  xxreadtoken(void)
784   pungetc();   pungetc();
785   goto breakloop;   goto breakloop;
786   case '\n':   case '\n':
787   plinno++;   lineno_inc();
788   needprompt = doprompt;   needprompt = doprompt;
789   RETURN(TNL);   RETURN(TNL);
790   case PEOF:   case PEOF:
# Line 836  readtoken1(int firstc, char const *synta Line 844  readtoken1(int firstc, char const *synta
844   int c = firstc;   int c = firstc;
845   char *out;   char *out;
846   int len;   int len;
  char line[EOFMARKLEN + 1];  
847   struct nodelist *bqlist;   struct nodelist *bqlist;
848   int quotef;   int quotef;
849   int dblquote;   int dblquote;
# Line 845  readtoken1(int firstc, char const *synta Line 852  readtoken1(int firstc, char const *synta
852   int parenlevel; /* levels of parens in arithmetic */   int parenlevel; /* levels of parens in arithmetic */
853   int dqvarnest; /* levels of variables expansion within double quotes */   int dqvarnest; /* levels of variables expansion within double quotes */
854   int oldstyle;   int oldstyle;
855   char const *prevsyntax = NULL; /* syntax before arithmetic */   /* syntax before arithmetic */
856     char const *uninitialized_var(prevsyntax);
857    
858   startlinno = plinno;   startlinno = plinno;
859   dblquote = 0;   dblquote = 0;
# Line 878  readtoken1(int firstc, char const *synta Line 886  readtoken1(int firstc, char const *synta
886   if (syntax == BASESYNTAX)   if (syntax == BASESYNTAX)
887   goto endword; /* exit outer loop */   goto endword; /* exit outer loop */
888   USTPUTC(c, out);   USTPUTC(c, out);
889   plinno++;   lineno_inc();
890   if (doprompt)   if (doprompt)
891   setprompt(2);   setprompt(2);
892   c = pgetc();   c = pgetc();
# Line 891  readtoken1(int firstc, char const *synta Line 899  readtoken1(int firstc, char const *synta
899   USTPUTC(CTLESC, out);   USTPUTC(CTLESC, out);
900   USTPUTC(c, out);   USTPUTC(c, out);
901   break;   break;
902   case CBACK: /* backslash */   /* backslash */
903     case CBACK:
904   c = pgetc2();   c = pgetc2();
905   if (c == PEOF) {   if (c == PEOF) {
906   USTPUTC(CTLESC, out);   USTPUTC(CTLESC, out);
# Line 909  readtoken1(int firstc, char const *synta Line 918  readtoken1(int firstc, char const *synta
918   eofmark != NULL   eofmark != NULL
919   )   )
920   ) {   ) {
  USTPUTC(CTLESC, out);  
921   USTPUTC('\\', out);   USTPUTC('\\', out);
922   }   }
923   if (SQSYNTAX[c] == CCTL)   USTPUTC(CTLESC, out);
  USTPUTC(CTLESC, out);  
924   USTPUTC(c, out);   USTPUTC(c, out);
925   quotef++;   quotef++;
926   }   }
# Line 930  quotemark: Line 937  quotemark:
937   dblquote = 1;   dblquote = 1;
938   goto quotemark;   goto quotemark;
939   case CENDQUOTE:   case CENDQUOTE:
940   if (eofmark != NULL && arinest == 0 &&   if (eofmark && !varnest)
     varnest == 0) {  
941   USTPUTC(c, out);   USTPUTC(c, out);
942   } else {   else {
943   if (dqvarnest == 0) {   if (dqvarnest == 0) {
944   syntax = BASESYNTAX;   syntax = BASESYNTAX;
945   dblquote = 0;   dblquote = 0;
# Line 966  quotemark: Line 972  quotemark:
972   --parenlevel;   --parenlevel;
973   } else {   } else {
974   if (pgetc() == ')') {   if (pgetc() == ')') {
975   if (--arinest == 0) {   USTPUTC(CTLENDARI, out);
976   USTPUTC(CTLENDARI, out);   if (!--arinest)
977   syntax = prevsyntax;   syntax = prevsyntax;
  if (syntax == DQSYNTAX)  
  dblquote = 1;  
  else  
  dblquote = 0;  
  } else  
  USTPUTC(')', out);  
978   } else {   } else {
979   /*   /*
980   * unbalanced parens   * unbalanced parens
# Line 1042  endword: Line 1042  endword:
1042   */   */
1043    
1044  checkend: {  checkend: {
1045   if (eofmark) {   if (realeofmark(eofmark)) {
1046     int markloc;
1047     char *p;
1048    
1049   if (c == PEOA) {   if (c == PEOA) {
1050   c = pgetc2();   c = pgetc2();
1051   }   }
# Line 1051  checkend: { Line 1054  checkend: {
1054   c = pgetc2();   c = pgetc2();
1055   }   }
1056   }   }
1057   if (c == *eofmark) {  
1058   if (pfgets(line, sizeof line) != NULL) {   markloc = out - (char *)stackblock();
1059   char *p, *q;   for (p = eofmark; STPUTC(c, out), *p; p++) {
1060     if (c != *p)
1061   p = line;   goto more_heredoc;
1062   for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);  
1063   if (*p == '\n' && *q == '\0') {   c = pgetc2();
1064   c = PEOF;   }
1065   plinno++;  
1066   needprompt = doprompt;   if (c == '\n' || c == PEOF) {
1067   } else {   c = PEOF;
1068   pushstring(line, NULL);   lineno_inc();
1069     needprompt = doprompt;
1070     } else {
1071     int len;
1072    
1073    more_heredoc:
1074     p = (char *)stackblock() + markloc + 1;
1075     len = out - p;
1076    
1077     if (len) {
1078     len -= c < 0;
1079     c = p[-1];
1080    
1081     if (len) {
1082     char *str;
1083    
1084     str = alloca(len + 1);
1085     *(char *)mempcpy(str, p, len) = 0;
1086    
1087     pushstring(str, NULL);
1088   }   }
1089   }   }
1090   }   }
1091    
1092     STADJUST((char *)stackblock() + markloc - out, out);
1093   }   }
1094   goto checkend_return;   goto checkend_return;
1095  }  }
# Line 1143  parseredir: { Line 1167  parseredir: {
1167  parsesub: {  parsesub: {
1168   int subtype;   int subtype;
1169   int typeloc;   int typeloc;
  int flags;  
1170   char *p;   char *p;
1171   static const char types[] = "}-+?=";   static const char types[] = "}-+?=";
1172    
1173   c = pgetc();   c = pgetc();
1174   if (   if (
1175     (checkkwd & CHKEOFMARK) ||
1176   c <= PEOA  ||   c <= PEOA  ||
1177   (c != '(' && c != '{' && !is_name(c) && !is_special(c))   (c != '(' && c != '{' && !is_name(c) && !is_special(c))
1178   ) {   ) {
# Line 1164  parsesub: { Line 1188  parsesub: {
1188   } else {   } else {
1189   USTPUTC(CTLVAR, out);   USTPUTC(CTLVAR, out);
1190   typeloc = out - (char *)stackblock();   typeloc = out - (char *)stackblock();
1191   USTPUTC(VSNORMAL, out);   STADJUST(1, out);
1192   subtype = VSNORMAL;   subtype = VSNORMAL;
1193   if (c == '{') {   if (likely(c == '{')) {
1194   c = pgetc();   c = pgetc();
1195   if (c == '#') {   subtype = 0;
  if ((c = pgetc()) == '}')  
  c = '#';  
  else  
  subtype = VSLENGTH;  
  }  
  else  
  subtype = 0;  
1196   }   }
1197   if (c > PEOA && is_name(c)) {  varname:
1198     if (is_name(c)) {
1199   do {   do {
1200   STPUTC(c, out);   STPUTC(c, out);
1201   c = pgetc();   c = pgetc();
1202   } while (c > PEOA && is_in_name(c));   } while (is_in_name(c));
1203   } else if (is_digit(c)) {   } else if (is_digit(c)) {
1204   do {   do {
1205   STPUTC(c, out);   STPUTC(c, out);
# Line 1189  parsesub: { Line 1207  parsesub: {
1207   } while (is_digit(c));   } while (is_digit(c));
1208   }   }
1209   else if (is_special(c)) {   else if (is_special(c)) {
1210   USTPUTC(c, out);   int cc = c;
1211    
1212   c = pgetc();   c = pgetc();
1213    
1214     if (!subtype && cc == '#') {
1215     subtype = VSLENGTH;
1216    
1217     if (c == '_' || isalnum(c))
1218     goto varname;
1219    
1220     cc = c;
1221     c = pgetc();
1222     if (cc == '}' || c != '}') {
1223     pungetc();
1224     subtype = 0;
1225     c = cc;
1226     cc = '#';
1227     }
1228     }
1229    
1230     USTPUTC(cc, out);
1231   }   }
1232   else   else
1233  badsub: synerror("Bad substitution");   goto badsub;
1234    
  STPUTC('=', out);  
  flags = 0;  
1235   if (subtype == 0) {   if (subtype == 0) {
1236   switch (c) {   switch (c) {
1237   case ':':   case ':':
1238   flags = VSNUL;   subtype = VSNUL;
1239   c = pgetc();   c = pgetc();
1240   /*FALLTHROUGH*/   /*FALLTHROUGH*/
1241   default:   default:
1242   p = strchr(types, c);   p = strchr(types, c);
1243   if (p == NULL)   if (p == NULL)
1244   goto badsub;   break;
1245   subtype = p - types + VSNORMAL;   subtype |= p - types + VSNORMAL;
1246   break;   break;
1247   case '%':   case '%':
1248   case '#':   case '#':
# Line 1224  badsub: synerror("Bad substitution"); Line 1259  badsub: synerror("Bad substitution");
1259   }   }
1260   }   }
1261   } else {   } else {
1262    badsub:
1263   pungetc();   pungetc();
1264   }   }
1265   if (dblquote || arinest)   *((char *)stackblock() + typeloc) = subtype;
  flags |= VSQUOTE;  
  *((char *)stackblock() + typeloc) = subtype | flags;  
1266   if (subtype != VSNORMAL) {   if (subtype != VSNORMAL) {
1267   varnest++;   varnest++;
1268   if (dblquote || arinest) {   if (dblquote)
1269   dqvarnest++;   dqvarnest++;
  }  
1270   }   }
1271     STPUTC('=', out);
1272   }   }
1273   goto parsesub_return;   goto parsesub_return;
1274  }  }
# Line 1252  parsebackq: { Line 1286  parsebackq: {
1286   union node *n;   union node *n;
1287   char *str;   char *str;
1288   size_t savelen;   size_t savelen;
1289   int saveprompt = 0;   int uninitialized_var(saveprompt);
1290    
1291   str = NULL;   str = NULL;
1292   savelen = out - (char *)stackblock();   savelen = out - (char *)stackblock();
# Line 1281  parsebackq: { Line 1315  parsebackq: {
1315    
1316   case '\\':   case '\\':
1317                                  if ((pc = pgetc()) == '\n') {                                  if ((pc = pgetc()) == '\n') {
1318   plinno++;   lineno_inc();
1319   if (doprompt)   if (doprompt)
1320   setprompt(2);   setprompt(2);
1321   /*   /*
# Line 1306  parsebackq: { Line 1340  parsebackq: {
1340   synerror("EOF in backquote substitution");   synerror("EOF in backquote substitution");
1341    
1342   case '\n':   case '\n':
1343   plinno++;   lineno_inc();
1344   needprompt = doprompt;   needprompt = doprompt;
1345   break;   break;
1346    
# Line 1359  done: Line 1393  done:
1393   memcpy(out, str, savelen);   memcpy(out, str, savelen);
1394   STADJUST(savelen, out);   STADJUST(savelen, out);
1395   }   }
1396   if (arinest || dblquote)   USTPUTC(CTLBACKQ, out);
  USTPUTC(CTLBACKQ | CTLQUOTE, out);  
  else  
  USTPUTC(CTLBACKQ, out);  
1397   if (oldstyle)   if (oldstyle)
1398   goto parsebackq_oldreturn;   goto parsebackq_oldreturn;
1399   else   else
# Line 1377  parsearith: { Line 1408  parsearith: {
1408   if (++arinest == 1) {   if (++arinest == 1) {
1409   prevsyntax = syntax;   prevsyntax = syntax;
1410   syntax = ARISYNTAX;   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);  
1411   }   }
1412     USTPUTC(CTLARI, out);
1413   goto parsearith_return;   goto parsearith_return;
1414  }  }
1415    
# Line 1404  RESET { Line 1425  RESET {
1425  }  }
1426  #endif  #endif
1427    
 /*  
  * Returns true if the text contains nothing to expand (no dollar signs  
  * or backquotes).  
  */  
   
 STATIC int  
 noexpand(char *text)  
 {  
  char *p;  
  signed char c;  
   
  p = text;  
  while ((c = *p++) != '\0') {  
  if (c == CTLQUOTEMARK)  
  continue;  
  if (c == CTLESC)  
  p++;  
  else if (BASESYNTAX[(int)c] == CCTL)  
  return 0;  
  }  
  return 1;  
 }  
   
1428    
1429  /*  /*
1430   * Return of a legal variable name (a letter or underscore followed by zero or   * Return of a legal variable name (a letter or underscore followed by zero or
# Line 1493  setprompt(int which) Line 1491  setprompt(int which)
1491   show = !el;   show = !el;
1492  #endif  #endif
1493   if (show) {   if (show) {
1494   setstackmark(&smark);   pushstackmark(&smark, stackblocksize());
  stalloc(stackblocksize());  
1495   out2str(getprompt(NULL));   out2str(getprompt(NULL));
1496   popstackmark(&smark);   popstackmark(&smark);
1497   }   }
# Line 1504  const char * Line 1501  const char *
1501  expandstr(const char *ps)  expandstr(const char *ps)
1502  {  {
1503   union node n;   union node n;
1504     int saveprompt;
1505    
1506   /* XXX Fix (char *) cast. */   /* XXX Fix (char *) cast. */
1507   setinputstring((char *)ps);   setinputstring((char *)ps);
1508   readtoken1(pgetc(), DQSYNTAX, nullstr, 0);  
1509     saveprompt = doprompt;
1510     doprompt = 0;
1511    
1512     readtoken1(pgetc(), DQSYNTAX, FAKEEOFMARK, 0);
1513    
1514     doprompt = saveprompt;
1515    
1516   popfile();   popfile();
1517    
1518   n.narg.type = NARG;   n.narg.type = NARG;
# Line 1515  expandstr(const char *ps) Line 1520  expandstr(const char *ps)
1520   n.narg.text = wordtext;   n.narg.text = wordtext;
1521   n.narg.backquote = backquotelist;   n.narg.backquote = backquotelist;
1522    
1523   expandarg(&n, NULL, 0);   expandarg(&n, NULL, EXP_QUOTED);
1524   return stackblock();   return stackblock();
1525  }  }
1526    

Legend:
Removed from v.1121  
changed lines
  Added in v.1122