tr: support octal ranges
authorRichard Genoud <richard.genoud@gmail.com>
Mon, 26 Oct 2015 09:10:28 +0000 (10:10 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 26 Oct 2015 16:18:07 +0000 (17:18 +0100)
now, we can do printf "a\tb\tcdef\n" | ./busybox tr -d "\1-\14b-e"
af

and bonus, we save some bytes.

function                                             old     new   delta
expand                                               718     699     -19
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-19)             Total: -19
bytes

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/tr.c

index e67948a36c88a148f22cd6a5af97e75159cfefa1..2f49d5a86ac613bb898e4658551600c3ee62b608 100644 (file)
@@ -91,7 +91,6 @@ static void map(char *pvector,
  *   Character classes, e.g. [:upper:] ==> A...Z
  *   Equiv classess, e.g. [=A=] ==> A   (hmmmmmmm?)
  * not supported:
- *   \ooo-\ooo - octal ranges
  *   [x*N] - repeat char x N times
  *   [x*] - repeat char x until it fills STRING2:
  * # echo qwe123 | /usr/bin/tr 123456789 '[d]'
@@ -99,7 +98,7 @@ static void map(char *pvector,
  * # echo qwe123 | /usr/bin/tr 123456789 '[d*]'
  * qweddd
  */
-static unsigned expand(const char *arg, char **buffer_p)
+static unsigned expand(char *arg, char **buffer_p)
 {
        char *buffer = *buffer_p;
        unsigned pos = 0;
@@ -113,9 +112,17 @@ static unsigned expand(const char *arg, char **buffer_p)
                        *buffer_p = buffer = xrealloc(buffer, size);
                }
                if (*arg == '\\') {
+                       const char *z;
                        arg++;
-                       buffer[pos++] = bb_process_escape_sequence(&arg);
-                       continue;
+                       z = arg;
+                       ac = bb_process_escape_sequence(&z);
+                       arg = (char *)z;
+                       arg--;
+                       *arg = ac;
+                       /*
+                        * fall through, there may be a range.
+                        * If not, current char will be treated anyway.
+                        */
                }
                if (arg[1] == '-') { /* "0-9..." */
                        ac = arg[2];
@@ -124,9 +131,15 @@ static unsigned expand(const char *arg, char **buffer_p)
                                continue; /* next iter will copy '-' and stop */
                        }
                        i = (unsigned char) *arg;
+                       arg += 3; /* skip 0-9 or 0-\ */
+                       if (ac == '\\') {
+                               const char *z;
+                               z = arg;
+                               ac = bb_process_escape_sequence(&z);
+                               arg = (char *)z;
+                       }
                        while (i <= ac) /* ok: i is unsigned _int_ */
                                buffer[pos++] = i++;
-                       arg += 3; /* skip 0-9 */
                        continue;
                }
                if ((ENABLE_FEATURE_TR_CLASSES || ENABLE_FEATURE_TR_EQUIV)