Page MenuHomeFreeBSD

D49201.diff
No OneTemporary

D49201.diff

Index: bin/sh/options.h
===================================================================
--- bin/sh/options.h
+++ bin/sh/options.h
@@ -68,9 +68,10 @@
#define nologflag optval[19]
#define pipefailflag optval[20]
#define verifyflag optval[21]
+#define braceexpandflag optval[22]
#define NSHORTOPTS 19
-#define NOPTS 22
+#define NOPTS 23
extern char optval[NOPTS];
extern const char optletter[NSHORTOPTS];
@@ -100,6 +101,7 @@
"\005nolog"
"\010pipefail"
"\006verify"
+ "\013braceexpand"
;
#endif
Index: bin/sh/parser.c
===================================================================
--- bin/sh/parser.c
+++ bin/sh/parser.c
@@ -39,7 +39,9 @@
#endif /* not lint */
#include <sys/cdefs.h>
#include <sys/param.h>
+#include <ctype.h>
#include <pwd.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
@@ -132,6 +134,7 @@
static void setprompt(int);
static int pgetc_linecont(void);
static void getusername(char *, size_t);
+static bool expandbrace(FILE *, const char *);
static void *
@@ -820,6 +823,174 @@
return (t);
}
+static bool expandsequence(FILE *stream, const char prefix[static 1], const char *pattern) {
+ char format[] = "%0.*d%.*s";
+ int start, end, step, i;
+ const char *p, *close;
+ char *portal, *endptr;
+ const char *terminator = strchr(pattern, '\0');
+ int prefixlen = (int)(pattern - prefix - 1);
+ int size = prefixlen + 32;
+ int zeroes = 0;
+
+ /* Parse start value (letter or number) */
+ if (isalpha(pattern[0])) {
+ start = pattern[0];
+ p = pattern + 1;
+ } else if (isspace(pattern[0]))
+ /* strtol accepts space here, brace expansion doesn't */
+ return false;
+ else {
+ zeroes = strspn(pattern, "0");
+ start = strtol(pattern + zeroes, &endptr, 10);
+ if (pattern == endptr)
+ return false;
+ p = endptr;
+ }
+
+ /* Verify ".." separator */
+ if (*p++ != '.' || *p++ != '.')
+ return false;
+
+ /* Parse end value (must match type of start) */
+ if (isalpha(p[0])) {
+ if (!isalpha(pattern[0]))
+ return false;
+ end = *p++;
+ format[4] = 'c';
+ } else if (isspace(p[0]))
+ return false;
+ else {
+ int z = strspn(p, "0");
+
+ if (z > zeroes)
+ zeroes = z;
+ close = p + z;
+ end = strtol(close, &endptr, 10);
+ if (close == endptr)
+ return false;
+ p = endptr;
+ }
+
+ /* Parse optional step value */
+ if (*p == '}')
+ step = 1;
+ else if (*p++ == '.' && *p++ == '.') {
+ if (*p == '+' || *p == '-')
+ p++; /* Direction will be determined by testing start > end */
+ if (!isdigit(*p))
+ return false;
+ step = strtol(p, &endptr, 10);
+ if (*endptr != '}')
+ return false;
+ p = endptr;
+ } else
+ return false;
+ close = p;
+
+ /* Each of the generated terms will start from the same prefix */
+ if (!(portal = malloc(size)))
+ return false;
+ snprintf(portal, size, "%.*s", prefixlen, prefix);
+ size -= prefixlen;
+
+ /* Generate sequence */
+ i = start;
+ if (start > end)
+ step = -step;
+ goto first_iteration;
+ while (start > end ? i >= end : i <= end) {
+ if (isalpha(pattern[0]) && !isalpha(i))
+ break;
+ fputc(' ', stream);
+first_iteration:
+ /* Copy the generated term and the suffix */
+ snprintf(portal + prefixlen, size, format,
+ zeroes + 1, i, (int)(terminator - close), close + 1);
+
+ /* The string may be a brace expansion pattern too */
+ expandbrace(stream, portal);
+ i += step;
+ }
+ free(portal);
+
+ return true;
+}
+
+static bool expandbrace(FILE *stream, const char pattern[static 1]) {
+ const char *close, *separator, *last;
+ int prefixlen;
+ char *portal;
+ const char *open = pattern;
+ const char *end = strchr(pattern, '\0');
+ int size = end - pattern;
+
+ /* Unescaped braces and one of the separators are required */
+ if (open && open[0] != '{')
+ while ((open = strchr(open + 1, '{'))) {
+ if (open[-1] == '\\')
+ continue;
+ if (open[-1] != '$')
+ break;
+ /* '${' restarts the search for '{' from the closest '}' */
+ if (!(open = strchr(open + 1, '}')))
+ break;
+ }
+
+ /* When checking for sequence, don't go past the first closing brace */
+ if (open && (separator = strpbrk(open + 1, ".}")))
+ if (separator[0] == '.' && separator[1] == '.')
+ if (expandsequence(stream, pattern, open + 1))
+ return true;
+
+ /* If not a sequence, the comma is required */
+ if ((separator = open))
+ while ((separator = strchr(separator + 1, ',')))
+ if (separator[-1] != '\\')
+ break;
+
+ /* Only look for closing brace once the comma has been found */
+ if ((close = separator))
+ while ((close = strchr(close + 1, '}')))
+ if (close[-1] != '\\')
+ break;
+
+ /* Not a brace expansion pattern, treat literally */
+ if (!close || !(portal = malloc(size))) {
+ fputs(pattern, stream);
+ return false;
+ }
+
+ /* Each of the generated alternatives will start from the same prefix */
+ prefixlen = snprintf(portal, size, "%.*s",
+ (int)(open - pattern), pattern);
+ size -= prefixlen;
+
+ /* Generate alternatives */
+ last = open + 1;
+ goto first_iteration;
+ for (;;) {
+ fputc(' ', stream);
+first_iteration:
+ /* Copy the generated alternative and the suffix */
+ snprintf(portal + prefixlen, size, "%.*s%.*s",
+ (int)((separator ? separator : close) - last), last,
+ (int)(end - close), close + 1);
+
+ /* The string may be a brace expansion pattern too */
+ expandbrace(stream, portal);
+
+ /* Find the next alternative */
+ if (!separator)
+ break;
+ last = separator + 1;
+ separator = memchr(last, ',', close - separator - 1);
+ }
+ free(portal);
+ return true;
+}
+
+
static int
readtoken(void)
{
@@ -863,6 +1034,23 @@
pushstring(ap->val, strlen(ap->val), ap);
goto top;
}
+ if (braceexpandflag && wordtext != NULL) {
+ FILE *memstream;
+ char *buf;
+ size_t len;
+ bool expanded;
+
+ if ((memstream = open_memstream(&buf, &len)) == NULL)
+ goto out;
+
+ expanded = expandbrace(memstream, wordtext);
+ fclose(memstream);
+
+ if (expanded) {
+ pushstring(buf, len, NULL);
+ goto top;
+ }
+ }
}
out:
if (t != TNOT)
Index: bin/sh/sh.1
===================================================================
--- bin/sh/sh.1
+++ bin/sh/sh.1
@@ -364,6 +364,8 @@
when sourcing files or loading profiles.
.\" See also
.\" .Xr mac_veriexec 4 . TODO Does not exist; write it.
+.It Li braceexpand
+Enable brace expansion.
.El
.Pp
The

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 20, 3:49 AM (21 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17225525
Default Alt Text
D49201.diff (6 KB)

Event Timeline