summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-04-20 05:54:21 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-04-20 06:47:40 (GMT)
commit3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64 (patch) (unidiff)
treea3c83a584f8e2b54e294ff1dfa04a2262459d5a4
parent1498bd570eb001a6b2bc3f1a5074e8b384d6db30 (diff)
downloadgrecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.gz
grecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.bz2
Improve variable handling in wordsplit.
Positional variables ($N and ${N}) are recognized. Variable names in curly braces follow the same rules as unadorned ones. This commit also changes memory reallocation strategy in wsplt_assign_var. If ws_envbuf needs to be expanded, new allocation size is selected as 3/2 of the previous allocation, if that size is less than max(size_t).
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/wordsplit.h16
-rw-r--r--src/wordsplit.c67
2 files changed, 60 insertions, 23 deletions
diff --git a/include/wordsplit.h b/include/wordsplit.h
index 1a047f7..3a7ab25 100644
--- a/include/wordsplit.h
+++ b/include/wordsplit.h
@@ -1,5 +1,5 @@
1/* wordsplit - a word splitter 1/* wordsplit - a word splitter
2 Copyright (C) 2009-2018 Sergey Poznyakoff 2 Copyright (C) 2009-2019 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify it 4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the 5 under the terms of the GNU General Public License as published by the
@@ -66,9 +66,15 @@ struct wordsplit
66 const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of 66 const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
67 environment variables. */ 67 environment variables. */
68 68
69 char **ws_envbuf; 69 /* Temporary storage for environment variables. It is initialized
70 size_t ws_envidx; 70 upon first assignment which occurs during the parsing process
71 size_t ws_envsiz; 71 (e.g. ${x:=2}). When this happens, all variables from ws_env are
72 moved to ws_envbuf first, and the ws_envbuf address is assigned
73 to ws_env. From this moment on, all variable expansions are served
74 from ws_envbuf. */
75 char **ws_envbuf; /* Storage for variables */
76 size_t ws_envidx; /* Index of first free slot */
77 size_t ws_envsiz; /* Size of the ws_envbuf array */
72 78
73 int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); 79 int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
74 /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up 80 /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
@@ -197,8 +203,8 @@ struct wordsplit
197#define WRDSO_DOTGLOB 0x00000004 203#define WRDSO_DOTGLOB 0x00000004
198#if 0 /* Unused value */ 204#if 0 /* Unused value */
199#define WRDSO_ARGV 0x00000008 205#define WRDSO_ARGV 0x00000008
200/* Keep backslash in unrecognized escape sequences in words */
201#endif 206#endif
207/* Keep backslash in unrecognized escape sequences in words */
202#define WRDSO_BSKEEP_WORD 0x00000010 208#define WRDSO_BSKEEP_WORD 0x00000010
203/* Handle octal escapes in words */ 209/* Handle octal escapes in words */
204#define WRDSO_OESC_WORD 0x00000020 210#define WRDSO_OESC_WORD 0x00000020
diff --git a/src/wordsplit.c b/src/wordsplit.c
index bad59b1..f94015a 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -1086,12 +1086,16 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
1086 } 1086 }
1087 else 1087 else
1088 { 1088 {
1089 wsp->ws_envsiz *= 2; 1089 size_t n = wsp->ws_envsiz;
1090 newenv = realloc (wsp->ws_envbuf, 1090
1091 wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0])); 1091 if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_envbuf[0]) <= n)
1092 return _wsplt_nomem (wsp);
1093 n += (n + 1) / 2;
1094 newenv = realloc (wsp->ws_envbuf, n * sizeof (wsp->ws_envbuf[0]));
1092 if (!newenv) 1095 if (!newenv)
1093 return _wsplt_nomem (wsp); 1096 return _wsplt_nomem (wsp);
1094 wsp->ws_envbuf = newenv; 1097 wsp->ws_envbuf = newenv;
1098 wsp->ws_envsiz = n;
1095 wsp->ws_env = (const char**) wsp->ws_envbuf; 1099 wsp->ws_env = (const char**) wsp->ws_envbuf;
1096 } 1100 }
1097 } 1101 }
@@ -1128,6 +1132,29 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
1128 return WRDSE_OK; 1132 return WRDSE_OK;
1129} 1133}
1130 1134
1135/* Recover from what looked like a variable reference, but turned out
1136 not to be one. STR points to first character after '$'. */
1137static int
1138expvar_recover (struct wordsplit *wsp, const char *str,
1139 struct wordsplit_node **ptail, const char **pend, int flg)
1140{
1141 struct wordsplit_node *newnode;
1142
1143 if (wsnode_new (wsp, &newnode))
1144 return 1;
1145 wsnode_insert (wsp, newnode, *ptail, 0);
1146 *ptail = newnode;
1147 newnode->flags = _WSNF_WORD | flg;
1148 newnode->v.word = malloc (3);
1149 if (!newnode->v.word)
1150 return _wsplt_nomem (wsp);
1151 newnode->v.word[0] = '$';
1152 newnode->v.word[1] = str[0];
1153 newnode->v.word[2] = 0;
1154 *pend = str;
1155 return 0;
1156}
1157
1131static int 1158static int
1132expvar (struct wordsplit *wsp, const char *str, size_t len, 1159expvar (struct wordsplit *wsp, const char *str, size_t len,
1133 struct wordsplit_node **ptail, const char **pend, int flg) 1160 struct wordsplit_node **ptail, const char **pend, int flg)
@@ -1148,7 +1175,12 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1148 break; 1175 break;
1149 *pend = str + i - 1; 1176 *pend = str + i - 1;
1150 } 1177 }
1151 else if (str[0] == '{') 1178 else if (ISDIGIT (str[0]))
1179 {
1180 i = 1;
1181 *pend = str;
1182 }
1183 else if (str[0] == '{' && (ISVARBEG (str[1]) || ISDIGIT (str[1])))
1152 { 1184 {
1153 str++; 1185 str++;
1154 len--; 1186 len--;
@@ -1180,25 +1212,24 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1180 *pend = str + j; 1212 *pend = str + j;
1181 break; 1213 break;
1182 } 1214 }
1215 else if (ISDIGIT (str[1]))
1216 {
1217 if (!ISDIGIT (str[i]))
1218 {
1219 return expvar_recover (wsp, str - 1, ptail, pend, flg);
1220 }
1221 }
1222 else if (!ISVARCHR (str[i]))
1223 {
1224 return expvar_recover (wsp, str - 1, ptail, pend, flg);
1225 }
1183 } 1226 }
1184 if (i == len) 1227 if (i == len)
1185 return _wsplt_seterr (wsp, WRDSE_CBRACE); 1228 return _wsplt_seterr (wsp, WRDSE_CBRACE);
1186 } 1229 }
1187 else 1230 else
1188 { 1231 {
1189 if (wsnode_new (wsp, &newnode)) 1232 return expvar_recover (wsp, str, ptail, pend, flg);
1190 return 1;
1191 wsnode_insert (wsp, newnode, *ptail, 0);
1192 *ptail = newnode;
1193 newnode->flags = _WSNF_WORD | flg;
1194 newnode->v.word = malloc (3);
1195 if (!newnode->v.word)
1196 return _wsplt_nomem (wsp);
1197 newnode->v.word[0] = '$';
1198 newnode->v.word[1] = str[0];
1199 newnode->v.word[2] = 0;
1200 *pend = str;
1201 return 0;
1202 } 1233 }
1203 1234
1204 /* Actually expand the variable */ 1235 /* Actually expand the variable */
@@ -1417,7 +1448,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1417static int 1448static int
1418begin_var_p (int c) 1449begin_var_p (int c)
1419{ 1450{
1420 return c == '{' || ISVARBEG (c); 1451 return c == '{' || ISVARBEG (c) || ISDIGIT (c);
1421} 1452}
1422 1453
1423static int 1454static int

Return to:

Send suggestions and report system problems to the System administrator.