diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-10-24 10:22:38 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-12-17 15:25:24 +0200 |
commit | 9dcef9e579d2e06f294dabe7918fe6753054e6cb (patch) | |
tree | 6f9b91acf9df5f6f3b1881cc031bcad2fdd98f16 /src | |
parent | 49b4b7e2e45bd22992df25ab999cb8c3ed73930f (diff) | |
download | grecs-9dcef9e579d2e06f294dabe7918fe6753054e6cb.tar.gz grecs-9dcef9e579d2e06f294dabe7918fe6753054e6cb.tar.bz2 |
wordsplit: implement tilde and pathname expansion
* src/wordsplit.c (wordsplit_tildexpand)
(wordsplit_pathexpand): New functions.
(wordsplit_process_list): Run tilde and pathname expansion
if WRDSF_PATHEXPAND flag is set.
* src/wordsplit.h (wordsplit)<ws_options>: New member.
(WRDSF_PATHEXPAND): New flag.
(WRDSO_NULLGLOB,WRDSO_FAILGLOB)
(WRDSO_DOTGLOB): New defines.
* tests/wsp.c: New options pathexpand, nullglob, failglob,
dotglob. Fix help output.
Diffstat (limited to 'src')
-rw-r--r-- | src/wordsplit.c | 214 | ||||
-rw-r--r-- | src/wordsplit.h | 13 |
2 files changed, 225 insertions, 2 deletions
diff --git a/src/wordsplit.c b/src/wordsplit.c index f0170e1..6b01887 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | #include <stdarg.h> | 27 | #include <stdarg.h> |
28 | #include <pwd.h> | ||
29 | #include <glob.h> | ||
28 | 30 | ||
29 | #if ENABLE_NLS | 31 | #if ENABLE_NLS |
30 | # include <gettext.h> | 32 | # include <gettext.h> |
@@ -1210,6 +1212,195 @@ wordsplit_trimws (struct wordsplit *wsp) | |||
1210 | } | 1212 | } |
1211 | 1213 | ||
1212 | static int | 1214 | static int |
1215 | wordsplit_tildexpand (struct wordsplit *wsp) | ||
1216 | { | ||
1217 | struct wordsplit_node *p; | ||
1218 | char *uname = NULL; | ||
1219 | size_t usize = 0; | ||
1220 | |||
1221 | for (p = wsp->ws_head; p; p = p->next) | ||
1222 | { | ||
1223 | const char *str; | ||
1224 | |||
1225 | if (p->flags & _WSNF_QUOTE) | ||
1226 | continue; | ||
1227 | |||
1228 | str = wsnode_ptr (wsp, p); | ||
1229 | if (str[0] == '~') | ||
1230 | { | ||
1231 | size_t i, size, dlen; | ||
1232 | size_t slen = wsnode_len (p); | ||
1233 | char *dir; | ||
1234 | struct passwd *pw; | ||
1235 | char *newstr; | ||
1236 | |||
1237 | for (i = 1; i < slen && str[i] != '/'; i++) | ||
1238 | ; | ||
1239 | if (i == slen) | ||
1240 | continue; | ||
1241 | if (i > 1) | ||
1242 | { | ||
1243 | if (i > usize) | ||
1244 | { | ||
1245 | char *p = realloc (uname, i); | ||
1246 | if (!p) | ||
1247 | { | ||
1248 | free (uname); | ||
1249 | return _wsplt_nomem (wsp); | ||
1250 | } | ||
1251 | uname = p; | ||
1252 | usize = i; | ||
1253 | } | ||
1254 | --i; | ||
1255 | memcpy (uname, str + 1, i); | ||
1256 | uname[i] = 0; | ||
1257 | pw = getpwnam (uname); | ||
1258 | } | ||
1259 | else | ||
1260 | pw = getpwuid (getuid ()); | ||
1261 | |||
1262 | if (!pw) | ||
1263 | continue; | ||
1264 | |||
1265 | dlen = strlen (pw->pw_dir); | ||
1266 | size = slen - i + dlen; | ||
1267 | newstr = malloc (size); | ||
1268 | if (!newstr) | ||
1269 | { | ||
1270 | free (uname); | ||
1271 | return _wsplt_nomem (wsp); | ||
1272 | } | ||
1273 | --size; | ||
1274 | |||
1275 | memcpy (newstr, pw->pw_dir, dlen); | ||
1276 | memcpy (newstr + dlen, str + i + 1, slen - i - 1); | ||
1277 | newstr[size] = 0; | ||
1278 | if (p->flags & _WSNF_WORD) | ||
1279 | free (p->v.word); | ||
1280 | p->v.word = newstr; | ||
1281 | p->flags |= _WSNF_WORD; | ||
1282 | } | ||
1283 | } | ||
1284 | free (uname); | ||
1285 | } | ||
1286 | |||
1287 | static int | ||
1288 | isglob (const char *s, int l) | ||
1289 | { | ||
1290 | while (l--) | ||
1291 | { | ||
1292 | if (strchr ("*?[", *s++)) | ||
1293 | return 1; | ||
1294 | } | ||
1295 | return 0; | ||
1296 | } | ||
1297 | |||
1298 | static int | ||
1299 | wordsplit_pathexpand (struct wordsplit *wsp) | ||
1300 | { | ||
1301 | struct wordsplit_node *p, *next; | ||
1302 | char *pattern = NULL; | ||
1303 | size_t patsize = 0; | ||
1304 | size_t slen; | ||
1305 | char *str; | ||
1306 | int flags = 0; | ||
1307 | |||
1308 | #ifdef GLOB_PERIOD | ||
1309 | if (wsp->ws_options & WRDSO_DOTGLOB) | ||
1310 | flags = GLOB_PERIOD; | ||
1311 | #endif | ||
1312 | |||
1313 | for (p = wsp->ws_head; p; p = next) | ||
1314 | { | ||
1315 | const char *str; | ||
1316 | |||
1317 | next = p->next; | ||
1318 | |||
1319 | if (p->flags & _WSNF_QUOTE) | ||
1320 | continue; | ||
1321 | |||
1322 | str = wsnode_ptr (wsp, p); | ||
1323 | slen = wsnode_len (p); | ||
1324 | |||
1325 | if (isglob (str, slen)) | ||
1326 | { | ||
1327 | int i; | ||
1328 | glob_t g; | ||
1329 | struct wordsplit_node *prev; | ||
1330 | |||
1331 | if (slen + 1 > patsize) | ||
1332 | { | ||
1333 | char *p = realloc (pattern, slen + 1); | ||
1334 | if (!p) | ||
1335 | return _wsplt_nomem (wsp); | ||
1336 | pattern = p; | ||
1337 | patsize = slen + 1; | ||
1338 | } | ||
1339 | memcpy (pattern, str, slen); | ||
1340 | pattern[slen] = 0; | ||
1341 | |||
1342 | switch (glob (pattern, flags, NULL, &g)) | ||
1343 | { | ||
1344 | case 0: | ||
1345 | break; | ||
1346 | |||
1347 | case GLOB_NOSPACE: | ||
1348 | free (pattern); | ||
1349 | return _wsplt_nomem (wsp); | ||
1350 | |||
1351 | case GLOB_NOMATCH: | ||
1352 | if (wsp->ws_options & WRDSO_NULLGLOB) | ||
1353 | { | ||
1354 | wsnode_remove (wsp, p); | ||
1355 | wsnode_free (p); | ||
1356 | } | ||
1357 | else if (wsp->ws_options & WRDSO_FAILGLOB) | ||
1358 | { | ||
1359 | char buf[128]; | ||
1360 | if (wsp->ws_errno == WRDSE_USERERR) | ||
1361 | free (wsp->ws_usererr); | ||
1362 | snprintf (buf, sizeof (buf), _("no files match pattern %s"), | ||
1363 | pattern); | ||
1364 | free (pattern); | ||
1365 | wsp->ws_usererr = strdup (buf); | ||
1366 | if (!wsp->ws_usererr) | ||
1367 | return _wsplt_nomem (wsp); | ||
1368 | else | ||
1369 | return _wsplt_seterr (wsp, WRDSE_USERERR); | ||
1370 | } | ||
1371 | continue; | ||
1372 | |||
1373 | default: | ||
1374 | free (pattern); | ||
1375 | return _wsplt_seterr (wsp, WRDSE_GLOBERR); | ||
1376 | } | ||
1377 | |||
1378 | prev = p; | ||
1379 | for (i = 0; i < g.gl_pathc; i++) | ||
1380 | { | ||
1381 | struct wordsplit_node *newnode; | ||
1382 | char *newstr; | ||
1383 | |||
1384 | if (wsnode_new (wsp, &newnode)) | ||
1385 | return 1; | ||
1386 | newstr = strdup (g.gl_pathv[i]); | ||
1387 | if (!newstr) | ||
1388 | return _wsplt_nomem (wsp); | ||
1389 | newnode->v.word = newstr; | ||
1390 | newnode->flags |= _WSNF_WORD|_WSNF_QUOTE; | ||
1391 | wsnode_insert (wsp, newnode, prev, 0); | ||
1392 | prev = newnode; | ||
1393 | } | ||
1394 | globfree (&g); | ||
1395 | |||
1396 | wsnode_remove (wsp, p); | ||
1397 | wsnode_free (p); | ||
1398 | } | ||
1399 | } | ||
1400 | free (pattern); | ||
1401 | } | ||
1402 | |||
1403 | static int | ||
1213 | skip_sed_expr (const char *command, size_t i, size_t len) | 1404 | skip_sed_expr (const char *command, size_t i, size_t len) |
1214 | { | 1405 | { |
1215 | int state; | 1406 | int state; |
@@ -1653,6 +1844,16 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start) | |||
1653 | } | 1844 | } |
1654 | } | 1845 | } |
1655 | 1846 | ||
1847 | if (wsp->ws_flags & WRDSF_PATHEXPAND) | ||
1848 | { | ||
1849 | wordsplit_tildexpand (wsp); | ||
1850 | if (wsp->ws_flags & WRDSF_SHOWDBG) | ||
1851 | { | ||
1852 | wsp->ws_debug ("After tilde expansion:"); | ||
1853 | wordsplit_dump_nodes (wsp); | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1656 | /* Expand variables */ | 1857 | /* Expand variables */ |
1657 | if (!(wsp->ws_flags & WRDSF_NOVAR)) | 1858 | if (!(wsp->ws_flags & WRDSF_NOVAR)) |
1658 | { | 1859 | { |
@@ -1709,6 +1910,16 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start) | |||
1709 | wordsplit_dump_nodes (wsp); | 1910 | wordsplit_dump_nodes (wsp); |
1710 | } | 1911 | } |
1711 | 1912 | ||
1913 | if (wsp->ws_flags & WRDSF_PATHEXPAND) | ||
1914 | { | ||
1915 | wordsplit_pathexpand (wsp); | ||
1916 | if (wsp->ws_flags & WRDSF_SHOWDBG) | ||
1917 | { | ||
1918 | wsp->ws_debug ("After path expan |