]> Zhao Yanbai Git Server - minix.git/commitdiff
Add character classes for tr
authorErik van der Kouwe <erik@minix3.org>
Mon, 25 Jan 2010 18:14:54 +0000 (18:14 +0000)
committerErik van der Kouwe <erik@minix3.org>
Mon, 25 Jan 2010 18:14:54 +0000 (18:14 +0000)
commands/simple/tr.c
man/man1/tr.1

index d3c64a8c89fa45bfbcf37ac51860fbe8bee0c00b..3f013418aef5ce99ec2c3108ea44625971fd1153 100644 (file)
@@ -117,11 +117,47 @@ register unsigned char *string1, *string2;
   }
 }
 
+static int starts_with(const char *s1, const char *s2)
+{
+       while (*s1 && *s1 == *s2)
+       {
+               s1++;
+               s2++;
+       }
+       return *s1 == 0;
+}
+
+/* 
+ * character classes from 
+ * http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
+ * missing: blank, punct, cntrl, graph, print, space 
+ */
+static struct
+{
+       const char *keyword;
+       char first;
+       char last;
+} expand_keywords[] = {
+       { "[:alnum:]", 'A', 'Z' },
+       { "[:alnum:]", 'a', 'z' },
+       { "[:alnum:]", '0', '9' },
+       { "[:alpha:]", 'A', 'Z' },
+       { "[:alpha:]", 'a', 'z' },
+       { "[:digit:]", '0', '9' },
+       { "[:lower:]", 'a', 'z' },
+       { "[:upper:]", 'A', 'Z' },
+       { "[:xdigit:]", '0', '9' },             
+       { "[:xdigit:]", 'A', 'F' },
+       { "[:xdigit:]", 'a', 'f' }
+};
+
+#define LENGTH(a) ((sizeof((a))) / (sizeof((a)[0])))
+
 void expand(arg, buffer)
 register char *arg;
 register unsigned char *buffer;
 {
-  int i, ac;
+  int i, ac, keyword_index;
 
   while (*arg) {
        if (*arg == '\\') {
@@ -136,16 +172,35 @@ register unsigned char *buffer;
                } else if (*arg != '\0')
                        *buffer++ = *arg++;
        } else if (*arg == '[') {
-               arg++;
-               i = *arg++;
-               if (*arg++ != '-') {
-                       *buffer++ = '[';
-                       arg -= 2;
-                       continue;
+               /* does one of the keywords match? */
+               keyword_index = -1;
+               for (i = 0; i < LENGTH(expand_keywords); i++)
+                       if (starts_with(expand_keywords[i].keyword, arg))
+                       {
+                               /* we have a match, remember and expand */
+                               keyword_index = i;
+                               ac = expand_keywords[i].first;
+                               while (ac <= expand_keywords[i].last)
+                                       *buffer++ = ac++;
+                       }
+
+               /* skip keyword if found, otherwise expand range */
+               if (keyword_index >= 0)
+                       arg += strlen(expand_keywords[keyword_index].keyword);
+               else
+               {
+                       /* expand range */
+                       arg++;
+                       i = *arg++;
+                       if (*arg++ != '-') {
+                               *buffer++ = '[';
+                               arg -= 2;
+                               continue;
+                       }
+                       ac = *arg++;
+                       while (i <= ac) *buffer++ = i++;
+                       arg++;          /* Skip ']' */
                }
-               ac = *arg++;
-               while (i <= ac) *buffer++ = i++;
-               arg++;          /* Skip ']' */
        } else
                *buffer++ = *arg++;
   }
index ffff98b1ac95a9ca1fc46e40ca0df7cf9c706d4f..05794ddea183e8565db1c40197dffd7b03f45bf1 100644 (file)
@@ -45,3 +45,12 @@ Use [ and ] if you want to be portable, because a
 .I tr
 that doesn't need them will still accept the syntax and mindlessly
 translate [ into [ and ] into ].
+.PP
+MINIX tr supports the following character classes: alnum, alpha, digit, lower,
+upper and xdigit. If any of these keywords is encountered between backets and 
+colons, it is replaced by respectively alphanumeric characters, alphabetic
+characters, decimal digits, lowercase letters, uppercase letters and 
+hexadecimal digits. The following are equivalent with the given examples:
+.EX "tr \(fm[:upper:]\(fm \(fm[:lower:]\(fm <x >y     " "Convert upper case to lower case"
+.EX "tr \-d \(fm[:digit:]\(fm <f1 >f2  " "Delete all digits from \fIf1\fR"
+