Date: Wed, 15 Jun 2011 21:48:10 +0000 (UTC) From: Jilles Tjoelker <jilles@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r223120 - in head: bin/sh tools/regression/bin/sh/builtins Message-ID: <201106152148.p5FLmAxr099439@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106152148.p5FLmAxr099439>