summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2014-10-24 07:22:38 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2015-12-17 13:25:24 (GMT)
commit9dcef9e579d2e06f294dabe7918fe6753054e6cb (patch) (side-by-side diff)
tree6f9b91acf9df5f6f3b1881cc031bcad2fdd98f16 /src
parent49b4b7e2e45bd22992df25ab999cb8c3ed73930f (diff)
downloadgrecs-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') (more/less context) (ignore whitespace changes)
-rw-r--r--src/wordsplit.c214
-rw-r--r--src/wordsplit.h13
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 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
+#include <pwd.h>
+#include <glob.h>
#if ENABLE_NLS
# include <gettext.h>
@@ -1210,6 +1212,195 @@ wordsplit_trimws (struct wordsplit *wsp)
}
static int
+wordsplit_tildexpand (struct wordsplit *wsp)
+{
+ struct wordsplit_node *p;
+ char *uname = NULL;
+ size_t usize = 0;
+
+ for (p = wsp->ws_head; p; p = p->next)
+ {
+ const char *str;
+
+ if (p->flags & _WSNF_QUOTE)
+ continue;
+
+ str = wsnode_ptr (wsp, p);
+ if (str[0] == '~')
+ {
+ size_t i, size, dlen;
+ size_t slen = wsnode_len (p);
+ char *dir;
+ struct passwd *pw;
+ char *newstr;
+
+ for (i = 1; i < slen && str[i] != '/'; i++)
+ ;
+ if (i == slen)
+ continue;
+ if (i > 1)
+ {
+ if (i > usize)
+ {
+ char *p = realloc (uname, i);
+ if (!p)
+ {
+ free (uname);
+ return _wsplt_nomem (wsp);
+ }
+ uname = p;
+ usize = i;
+ }
+ --i;
+ memcpy (uname, str + 1, i);
+ uname[i] = 0;
+ pw = getpwnam (uname);
+ }
+ else
+ pw = getpwuid (getuid ());
+
+ if (!pw)
+ continue;
+
+ dlen = strlen (pw->pw_dir);
+ size = slen - i + dlen;
+ newstr = malloc (size);
+ if (!newstr)
+ {
+ free (uname);
+ return _wsplt_nomem (wsp);
+ }
+ --size;
+
+ memcpy (newstr, pw->pw_dir, dlen);
+ memcpy (newstr + dlen, str + i + 1, slen - i - 1);
+ newstr[size] = 0;
+ if (p->flags & _WSNF_WORD)
+ free (p->v.word);
+ p->v.word = newstr;
+ p->flags |= _WSNF_WORD;
+ }
+ }
+ free (uname);
+}
+
+static int
+isglob (const char *s, int l)
+{
+ while (l--)
+ {
+ if (strchr ("*?[", *s++))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+wordsplit_pathexpand (struct wordsplit *wsp)
+{
+ struct wordsplit_node *p, *next;
+ char *pattern = NULL;
+ size_t patsize = 0;
+ size_t slen;
+ char *str;
+ int flags = 0;
+
+#ifdef GLOB_PERIOD
+ if (wsp->ws_options & WRDSO_DOTGLOB)
+ flags = GLOB_PERIOD;
+#endif
+
+ for (p = wsp->ws_head; p; p = next)
+ {
+ const char *str;
+
+ next = p->next;
+
+ if (p->flags & _WSNF_QUOTE)
+ continue;
+
+ str = wsnode_ptr (wsp, p);
+ slen = wsnode_len (p);
+
+ if (isglob (str, slen))
+ {
+ int i;
+ glob_t g;
+ struct wordsplit_node *prev;
+
+ if (slen + 1 > patsize)
+ {
+ char *p = realloc (pattern, slen + 1);
+ if (!p)
+ return _wsplt_nomem (wsp);
+ pattern = p;
+ patsize = slen + 1;
+ }
+ memcpy (pattern, str, slen);
+ pattern[slen] = 0;
+
+ switch (glob (pattern, flags, NULL, &g))
+ {
+ case 0:
+ break;
+
+ case GLOB_NOSPACE:
+ free (pattern);
+ return _wsplt_nomem (wsp);
+
+ case GLOB_NOMATCH:
+ if (wsp->ws_options & WRDSO_NULLGLOB)
+ {
+ wsnode_remove (wsp, p);
+ wsnode_free (p);
+ }
+ else if (wsp->ws_options & WRDSO_FAILGLOB)
+ {
+ char buf[128];
+ if (wsp->ws_errno == WRDSE_USERERR)
+ free (wsp->ws_usererr);
+ snprintf (buf, sizeof (buf), _("no files match pattern %s"),
+ pattern);
+ free (pattern);
+ wsp->ws_usererr = strdup (buf);
+ if (!wsp->ws_usererr)
+ return _wsplt_nomem (wsp);
+ else
+ return _wsplt_seterr (wsp, WRDSE_USERERR);
+ }
+ continue;
+
+ default:
+ free (pattern);
+ return _wsplt_seterr (wsp, WRDSE_GLOBERR);
+ }
+
+ prev = p;
+ for (i = 0; i < g.gl_pathc; i++)
+ {
+ struct wordsplit_node *newnode;
+ char *newstr;
+
+ if (wsnode_new (wsp, &newnode))
+ return 1;
+ newstr = strdup (g.gl_pathv[i]);
+ if (!newstr)
+ return _wsplt_nomem (wsp);
+ newnode->v.word = newstr;
+ newnode->flags |= _WSNF_WORD|_WSNF_QUOTE;
+ wsnode_insert (wsp, newnode, prev, 0);
+ prev = newnode;
+ }
+ globfree (&g);
+
+ wsnode_remove (wsp, p);
+ wsnode_free (p);
+ }
+ }
+ free (pattern);
+}
+
+static int
skip_sed_expr (const char *command, size_t i, size_t len)
{
int state;
@@ -1653,6 +1844,16 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
}
}
+ if (wsp->ws_flags & WRDSF_PATHEXPAND)
+ {
+ wordsplit_tildexpand (wsp);
+ if (wsp->ws_flags & WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("After tilde expansion:");
+ wordsplit_dump_nodes (wsp);
+ }
+ }
+
/* Expand variables */
if (!(wsp->ws_flags & WRDSF_NOVAR))
{
@@ -1709,6 +1910,16 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
wordsplit_dump_nodes (wsp);
}
+ if (wsp->ws_flags & WRDSF_PATHEXPAND)
+ {
+ wordsplit_pathexpand (wsp);
+ if (wsp->ws_flags & WRDSF_SHOWDBG)
+ {
+ wsp->ws_debug ("After path expansion:");
+ wordsplit_dump_nodes (wsp);
+ }
+ }
+
return wsp->ws_errno;
}
@@ -1823,7 +2034,8 @@ const char *_wordsplit_errstr[] = {
N_("unbalanced curly brace"),
N_("undefined variable"),
N_("input exhausted"),
- N_("unbalanced parenthesis")
+ N_("unbalanced parenthesis"),
+ N_("globbing error")
};
int _wordsplit_nerrs =
sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]);
diff --git a/src/wordsplit.h b/src/wordsplit.h
index eee262d..a531ac0 100644
--- a/src/wordsplit.h
+++ b/src/wordsplit.h
@@ -26,6 +26,7 @@ struct wordsplit
size_t ws_offs;
size_t ws_wordn;
int ws_flags;
+ int ws_options;
const char *ws_delim;
const char *ws_comment;
const char *ws_escape;
@@ -122,11 +123,20 @@ struct wordsplit
#define WRDSF_INCREMENTAL 0x20000000
/* ws_command needs argv parameter */
#define WRDSF_ARGV 0x40000000
+/* Perform pathname and tilde expansion */
+#define WRDSF_PATHEXPAND 0x80000000
#define WRDSF_DEFFLAGS \
(WRDSF_NOVAR | WRDSF_NOCMD | \
WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
+/* Remove the word that produces empty string after path expansion */
+#define WRDSO_NULLGLOB 0x01
+/* Print error message if path expansion produces empty string */
+#define WRDSO_FAILGLOB 0x02
+/* Allow a leading period to be matched by metacharacters. */
+#define WRDSO_DOTGLOB 0x04
+
#define WRDSE_OK 0
#define WRDSE_EOF WRDSE_OK
#define WRDSE_QUOTE 1
@@ -136,7 +146,8 @@ struct wordsplit
#define WRDSE_UNDEF 5
#define WRDSE_NOINPUT 6
#define WRDSE_PAREN 7
-#define WRDSE_USERERR 8
+#define WRDSE_GLOBERR 8
+#define WRDSE_USERERR 9
int wordsplit (const char *s, struct wordsplit *p, int flags);
int wordsplit_len (const char *s, size_t len,

Return to:

Send suggestions and report system problems to the System administrator.