svn commit: r223120 - in head: bin/sh tools/regression/bin/sh/builtins

Jilles Tjoelker jilles at FreeBSD.org
Wed Jun 15 21:48:10 UTC 2011


Author: jilles
Date: Wed Jun 15 21:48:10 2011
New Revision: 223120
URL: http://svn.freebsd.org/changeset/base/223120

Log:
  sh: Add support for named character classes in bracket expressions.
  
  Example:
    case x in [[:alpha:]]) echo yes ;; esac

Added:
  head/tools/regression/bin/sh/builtins/case8.0   (contents, props changed)
Modified:
  head/bin/sh/expand.c
  head/bin/sh/sh.1

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c	Wed Jun 15 20:34:40 2011	(r223119)
+++ head/bin/sh/expand.c	Wed Jun 15 21:48:10 2011	(r223120)
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <unistd.h>
 #include <wchar.h>
+#include <wctype.h>
 
 /*
  * Routines to expand arguments to commands.  We have to deal with
@@ -1401,13 +1402,43 @@ get_wc(const char **p)
 
 
 /*
+ * See if a character matches a character class, starting at the first colon
+ * of "[:class:]".
+ * If a valid character class is recognized, a pointer to the next character
+ * after the final closing bracket is stored into *end, otherwise a null
+ * pointer is stored into *end.
+ */
+static int
+match_charclass(const char *p, wchar_t chr, const char **end)
+{
+	char name[20];
+	const char *nameend;
+	wctype_t cclass;
+
+	*end = NULL;
+	p++;
+	nameend = strstr(p, ":]");
+	if (nameend == NULL || nameend - p >= sizeof(name) || nameend == p)
+		return 0;
+	memcpy(name, p, nameend - p);
+	name[nameend - p] = '\0';
+	*end = nameend + 2;
+	cclass = wctype(name);
+	/* An unknown class matches nothing but is valid nevertheless. */
+	if (cclass == 0)
+		return 0;
+	return iswctype(chr, cclass);
+}
+
+
+/*
  * Returns true if the pattern matches the string.
  */
 
 int
 patmatch(const char *pattern, const char *string, int squoted)
 {
-	const char *p, *q;
+	const char *p, *q, *end;
 	char c;
 	wchar_t wc, wc2;
 
@@ -1495,6 +1526,11 @@ patmatch(const char *pattern, const char
 			do {
 				if (c == CTLQUOTEMARK)
 					continue;
+				if (c == '[' && *p == ':') {
+					found |= match_charclass(p, chr, &end);
+					if (end != NULL)
+						p = end;
+				}
 				if (c == CTLESC)
 					c = *p++;
 				if (localeisutf8 && c & 0x80) {

Modified: head/bin/sh/sh.1
==============================================================================
--- head/bin/sh/sh.1	Wed Jun 15 20:34:40 2011	(r223119)
+++ head/bin/sh/sh.1	Wed Jun 15 21:48:10 2011	(r223120)
@@ -32,7 +32,7 @@
 .\"	from: @(#)sh.1	8.6 (Berkeley) 5/4/95
 .\" $FreeBSD$
 .\"
-.Dd June 12, 2011
+.Dd June 15, 2011
 .Dt SH 1
 .Os
 .Sh NAME
@@ -1648,6 +1648,15 @@ matches a
 rather than introducing a character class.
 A character class matches any of the characters between the square brackets.
 A range of characters may be specified using a minus sign.
+A named class of characters (see
+.Xr wctype 3 )
+may be specified by surrounding the name with
+.Ql \&[:
+and
+.Ql :\&] .
+For example,
+.Ql \&[\&[:alpha:\&]\&]
+is a shell pattern that matches a single letter.
 The character class may be complemented by making an exclamation point
 .Pq Ql !\&
 the first character of the character class.
@@ -2572,6 +2581,7 @@ will return the argument.
 .Xr execve 2 ,
 .Xr getrlimit 2 ,
 .Xr umask 2 ,
+.Xr wctype 3 ,
 .Xr editrc 5
 .Sh HISTORY
 A

Added: head/tools/regression/bin/sh/builtins/case8.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/builtins/case8.0	Wed Jun 15 21:48:10 2011	(r223120)
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+case aZ_ in
+[[:alpha:]_][[:upper:]_][[:alpha:]_]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[[:alpha:][:digit:]]) echo Failed at $LINENO ;;
+[![:alpha:][:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '.X.' in
+*[[:lower:]]*) echo Failed at $LINENO ;;
+*[[:upper:]]*) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[![:print:]]) echo Failed at $LINENO ;;
+[![:alnum:][:punct:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '
+' in
+[[:print:]]) echo Failed at $LINENO ;;
+['
+'[:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac


More information about the svn-src-all mailing list