Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/coreutils/tr.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/coreutils/tr.c

    r1765 r2725  
    1414 * by Erik Andersen <andersen@codepoet.org> to be used in busybox.
    1515 *
    16  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1717 */
    1818/* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
    19  * TODO: xdigit, graph, print
     19 * TODO: graph, print
    2020 */
     21
     22//kbuild:lib-$(CONFIG_TR) += tr.o
     23
     24//config:config TR
     25//config:   bool "tr"
     26//config:   default y
     27//config:   help
     28//config:     tr is used to squeeze, and/or delete characters from standard
     29//config:     input, writing to standard output.
     30//config:
     31//config:config FEATURE_TR_CLASSES
     32//config:   bool "Enable character classes (such as [:upper:])"
     33//config:   default y
     34//config:   depends on TR
     35//config:   help
     36//config:     Enable character classes, enabling commands such as:
     37//config:     tr [:upper:] [:lower:] to convert input into lowercase.
     38//config:
     39//config:config FEATURE_TR_EQUIV
     40//config:   bool "Enable equivalence classes"
     41//config:   default y
     42//config:   depends on TR
     43//config:   help
     44//config:     Enable equivalence classes, which essentially add the enclosed
     45//config:     character to the current set. For instance, tr [=a=] xyz would
     46//config:     replace all instances of 'a' with 'xyz'. This option is mainly
     47//config:     useful for cases when no other way of expressing a character
     48//config:     is possible.
     49
    2150#include "libbb.h"
    2251
    23 #define ASCII 0377
    24 
    25 #define TR_OPT_complement   (1<<0)
    26 #define TR_OPT_delete       (1<<1)
    27 #define TR_OPT_squeeze_reps (1<<2)
     52enum {
     53    ASCII = 256,
     54    /* string buffer needs to be at least as big as the whole "alphabet".
     55     * BUFSIZ == ASCII is ok, but we will realloc in expand
     56     * even for smallest patterns, let's avoid that by using *2:
     57     */
     58    TR_BUFSIZ = (BUFSIZ > ASCII*2) ? BUFSIZ : ASCII*2,
     59};
    2860
    2961static void map(char *pvector,
    30         unsigned char *string1, unsigned int string1_len,
    31         unsigned char *string2, unsigned int string2_len)
     62        char *string1, unsigned string1_len,
     63        char *string2, unsigned string2_len)
    3264{
    3365    char last = '0';
    34     unsigned int i, j;
     66    unsigned i, j;
    3567
    3668    for (j = 0, i = 0; i < string1_len; i++) {
    3769        if (string2_len <= j)
    38             pvector[string1[i]] = last;
     70            pvector[(unsigned char)(string1[i])] = last;
    3971        else
    40             pvector[string1[i]] = last = string2[j++];
     72            pvector[(unsigned char)(string1[i])] = last = string2[j++];
    4173    }
    4274}
    4375
    4476/* supported constructs:
    45  *   Ranges,  e.g.,  [0-9]  ==>  0123456789
    46  *   Escapes, e.g.,  \a     ==>  Control-G
    47  *   Character classes, e.g. [:upper:] ==> A ... Z
     77 *   Ranges,  e.g.,  0-9   ==>  0123456789
     78 *   Escapes, e.g.,  \a    ==>  Control-G
     79 *   Character classes, e.g. [:upper:] ==> A...Z
     80 *   Equiv classess, e.g. [=A=] ==> A   (hmmmmmmm?)
     81 * not supported:
     82 *   \ooo-\ooo - octal ranges
     83 *   [x*N] - repeat char x N times
     84 *   [x*] - repeat char x until it fills STRING2:
     85 * # echo qwe123 | /usr/bin/tr 123456789 '[d]'
     86 * qwe[d]
     87 * # echo qwe123 | /usr/bin/tr 123456789 '[d*]'
     88 * qweddd
    4889 */
    49 static unsigned int expand(const char *arg, char *buffer)
     90static unsigned expand(const char *arg, char **buffer_p)
    5091{
    51     char *buffer_start = buffer;
    52     unsigned i; /* XXX: FIXME: use unsigned char? */
     92    char *buffer = *buffer_p;
     93    unsigned pos = 0;
     94    unsigned size = TR_BUFSIZ;
     95    unsigned i; /* can't be unsigned char: must be able to hold 256 */
    5396    unsigned char ac;
    54 #define CLO ":]\0"
    55     static const char classes[] ALIGN1 =
    56         "alpha"CLO "alnum"CLO "digit"CLO "lower"CLO "upper"CLO "space"CLO
    57         "blank"CLO "punct"CLO "cntrl"CLO;
    58 #define CLASS_invalid 0 /* we increment the retval */
    59 #define CLASS_alpha 1
    60 #define CLASS_alnum 2
    61 #define CLASS_digit 3
    62 #define CLASS_lower 4
    63 #define CLASS_upper 5
    64 #define CLASS_space 6
    65 #define CLASS_blank 7
    66 #define CLASS_punct 8
    67 #define CLASS_cntrl 9
    68 //#define CLASS_xdigit 10
    69 //#define CLASS_graph 11
    70 //#define CLASS_print 12
     97
    7198    while (*arg) {
     99        if (pos + ASCII > size) {
     100            size += ASCII;
     101            *buffer_p = buffer = xrealloc(buffer, size);
     102        }
    72103        if (*arg == '\\') {
    73104            arg++;
    74             *buffer++ = bb_process_escape_sequence(&arg);
    75         } else if (*(arg+1) == '-') {
    76             ac = *(arg+2);
    77             if (ac == 0) {
    78                 *buffer++ = *arg++;
    79                 continue;
    80             }
    81             i = *arg;
    82             while (i <= ac)
    83                 *buffer++ = i++;
    84             arg += 3; /* Skip the assumed a-z */
    85         } else if (*arg == '[') {
     105            buffer[pos++] = bb_process_escape_sequence(&arg);
     106            continue;
     107        }
     108        if (arg[1] == '-') { /* "0-9..." */
     109            ac = arg[2];
     110            if (ac == '\0') { /* "0-": copy verbatim */
     111                buffer[pos++] = *arg++; /* copy '0' */
     112                continue; /* next iter will copy '-' and stop */
     113            }
     114            i = (unsigned char) *arg;
     115            while (i <= ac) /* ok: i is unsigned _int_ */
     116                buffer[pos++] = i++;
     117            arg += 3; /* skip 0-9 */
     118            continue;
     119        }
     120        if ((ENABLE_FEATURE_TR_CLASSES || ENABLE_FEATURE_TR_EQUIV)
     121         && *arg == '['
     122        ) {
    86123            arg++;
    87             i = *arg++;
    88             if (ENABLE_FEATURE_TR_CLASSES && i == ':') {
     124            i = (unsigned char) *arg++;
     125            /* "[xyz...". i=x, arg points to y */
     126            if (ENABLE_FEATURE_TR_CLASSES && i == ':') { /* [:class:] */
     127#define CLO ":]\0"
     128                static const char classes[] ALIGN1 =
     129                    "alpha"CLO "alnum"CLO "digit"CLO
     130                    "lower"CLO "upper"CLO "space"CLO
     131                    "blank"CLO "punct"CLO "cntrl"CLO
     132                    "xdigit"CLO;
     133                enum {
     134                    CLASS_invalid = 0, /* we increment the retval */
     135                    CLASS_alpha = 1,
     136                    CLASS_alnum = 2,
     137                    CLASS_digit = 3,
     138                    CLASS_lower = 4,
     139                    CLASS_upper = 5,
     140                    CLASS_space = 6,
     141                    CLASS_blank = 7,
     142                    CLASS_punct = 8,
     143                    CLASS_cntrl = 9,
     144                    CLASS_xdigit = 10,
     145                    //CLASS_graph = 11,
     146                    //CLASS_print = 12,
     147                };
    89148                smalluint j;
    90                 { /* not really pretty.. */
    91                     char *tmp = xstrndup(arg, 7); // warning: xdigit needs 8, not 7
    92                     j = index_in_strings(classes, tmp) + 1;
    93                     free(tmp);
    94                 }
    95                 if (j == CLASS_alnum || j == CLASS_digit) {
     149                char *tmp;
     150
     151                /* xdigit needs 8, not 7 */
     152                i = 7 + (arg[0] == 'x');
     153                tmp = xstrndup(arg, i);
     154                j = index_in_strings(classes, tmp) + 1;
     155                free(tmp);
     156
     157                if (j == CLASS_invalid)
     158                    goto skip_bracket;
     159
     160                arg += i;
     161                if (j == CLASS_alnum || j == CLASS_digit || j == CLASS_xdigit) {
    96162                    for (i = '0'; i <= '9'; i++)
    97                         *buffer++ = i;
     163                        buffer[pos++] = i;
    98164                }
    99165                if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) {
    100166                    for (i = 'A'; i <= 'Z'; i++)
    101                         *buffer++ = i;
     167                        buffer[pos++] = i;
    102168                }
    103169                if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) {
    104170                    for (i = 'a'; i <= 'z'; i++)
    105                         *buffer++ = i;
     171                        buffer[pos++] = i;
    106172                }
    107173                if (j == CLASS_space || j == CLASS_blank) {
    108                     *buffer++ = '\t';
     174                    buffer[pos++] = '\t';
    109175                    if (j == CLASS_space) {
    110                         *buffer++ = '\n';
    111                         *buffer++ = '\v';
    112                         *buffer++ = '\f';
    113                         *buffer++ = '\r';
     176                        buffer[pos++] = '\n';
     177                        buffer[pos++] = '\v';
     178                        buffer[pos++] = '\f';
     179                        buffer[pos++] = '\r';
    114180                    }
    115                     *buffer++ = ' ';
     181                    buffer[pos++] = ' ';
    116182                }
    117183                if (j == CLASS_punct || j == CLASS_cntrl) {
    118                     for (i = 0; i <= ASCII; i++)
    119                         if ((j == CLASS_punct &&
    120                              isprint(i) && (!isalnum(i)) && (!isspace(i))) ||
    121                             (j == CLASS_cntrl && iscntrl(i)))
    122                             *buffer++ = i;
    123                 }
    124                 if (j == CLASS_invalid) {
    125                     *buffer++ = '[';
    126                     *buffer++ = ':';
    127                     continue;
    128                 }
    129                 break;
    130             }
    131             if (ENABLE_FEATURE_TR_EQUIV && i == '=') {
    132                 *buffer++ = *arg;
    133                 arg += 3;   /* Skip the closing =] */
     184                    for (i = '\0'; i < ASCII; i++) {
     185                        if ((j == CLASS_punct && isprint_asciionly(i) && !isalnum(i) && !isspace(i))
     186                         || (j == CLASS_cntrl && iscntrl(i))
     187                        ) {
     188                            buffer[pos++] = i;
     189                        }
     190                    }
     191                }
     192                if (j == CLASS_xdigit) {
     193                    for (i = 'A'; i <= 'F'; i++) {
     194                        buffer[pos + 6] = i | 0x20;
     195                        buffer[pos++] = i;
     196                    }
     197                    pos += 6;
     198                }
    134199                continue;
    135200            }
    136             if (*arg++ != '-') {
    137                 *buffer++ = '[';
    138                 arg -= 2;
     201            /* "[xyz...", i=x, arg points to y */
     202            if (ENABLE_FEATURE_TR_EQUIV && i == '=') { /* [=CHAR=] */
     203                buffer[pos++] = *arg; /* copy CHAR */
     204                if (!arg[0] || arg[1] != '=' || arg[2] != ']')
     205                    bb_show_usage();
     206                arg += 3;  /* skip CHAR=] */
    139207                continue;
    140208            }
    141             ac = *arg++;
    142             while (i <= ac)
    143                 *buffer++ = i++;
    144             arg++;  /* Skip the assumed ']' */
    145         } else
    146             *buffer++ = *arg++;
    147     }
    148     return (buffer - buffer_start);
     209            /* The rest of "[xyz..." cases is treated as normal
     210             * string, "[" has no special meaning here:
     211             * tr "[a-z]" "[A-Z]" can be written as tr "a-z" "A-Z",
     212             * also try tr "[a-z]" "_A-Z+" and you'll see that
     213             * [] is not special here.
     214             */
     215 skip_bracket:
     216            arg -= 2; /* points to "[" in "[xyz..." */
     217        }
     218        buffer[pos++] = *arg++;
     219    }
     220    return pos;
    149221}
    150222
     223/* NB: buffer is guaranteed to be at least TR_BUFSIZE
     224 * (which is >= ASCII) big.
     225 */
    151226static int complement(char *buffer, int buffer_len)
    152227{
    153     int i, j, ix;
    154     char conv[ASCII + 2];
    155 
    156     ix = 0;
    157     for (i = 0; i <= ASCII; i++) {
    158         for (j = 0; j < buffer_len; j++)
    159             if (buffer[j] == i)
    160                 break;
    161         if (j == buffer_len)
    162             conv[ix++] = i & ASCII;
    163     }
    164     memcpy(buffer, conv, ix);
    165     return ix;
     228    int len;
     229    char conv[ASCII];
     230    unsigned char ch;
     231
     232    len = 0;
     233    ch = '\0';
     234    while (1) {
     235        if (memchr(buffer, ch, buffer_len) == NULL)
     236            conv[len++] = ch;
     237        if (++ch == '\0')
     238            break;
     239    }
     240    memcpy(buffer, conv, len);
     241    return len;
    166242}
    167243
    168 int tr_main(int argc, char **argv);
    169 int tr_main(int argc, char **argv)
     244int tr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     245int tr_main(int argc UNUSED_PARAM, char **argv)
    170246{
    171     unsigned char *ptr;
    172     int output_length = 0, input_length;
    173     int idx = 1;
    174247    int i;
    175     smalluint flags = 0;
    176     size_t read_chars = 0, in_index = 0, out_index = 0, c, coded, last = -1;
    177     RESERVE_CONFIG_UBUFFER(output, BUFSIZ);
    178     RESERVE_CONFIG_BUFFER(vector, ASCII+1);
    179     RESERVE_CONFIG_BUFFER(invec,  ASCII+1);
    180     RESERVE_CONFIG_BUFFER(outvec, ASCII+1);
    181 
    182     if (argc > 1 && argv[idx][0] == '-') {
    183         for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
    184             if (*ptr == 'c')
    185                 flags |= TR_OPT_complement;
    186             else if (*ptr == 'd')
    187                 flags |= TR_OPT_delete;
    188             else if (*ptr == 's')
    189                 flags |= TR_OPT_squeeze_reps;
    190             else
    191                 bb_show_usage();
    192         }
    193         idx++;
    194     }
    195     for (i = 0; i <= ASCII; i++) {
     248    smalluint opts;
     249    ssize_t read_chars;
     250    size_t in_index, out_index;
     251    unsigned last = UCHAR_MAX + 1; /* not equal to any char */
     252    unsigned char coded, c;
     253    char *str1 = xmalloc(TR_BUFSIZ);
     254    char *str2 = xmalloc(TR_BUFSIZ);
     255    int str2_length;
     256    int str1_length;
     257    char *vector = xzalloc(ASCII * 3);
     258    char *invec  = vector + ASCII;
     259    char *outvec = vector + ASCII * 2;
     260
     261#define TR_OPT_complement   (3 << 0)
     262#define TR_OPT_delete       (1 << 2)
     263#define TR_OPT_squeeze_reps (1 << 3)
     264
     265    for (i = 0; i < ASCII; i++) {
    196266        vector[i] = i;
    197         invec[i] = outvec[i] = FALSE;
    198     }
    199 
    200 #define tr_buf bb_common_bufsiz1
    201     if (argv[idx] != NULL) {
    202         input_length = expand(argv[idx++], tr_buf);
    203         if (flags & TR_OPT_complement)
    204             input_length = complement(tr_buf, input_length);
    205         if (argv[idx] != NULL) {
    206             if (*argv[idx] == '\0')
    207                 bb_error_msg_and_die("STRING2 cannot be empty");
    208             output_length = expand(argv[idx], output);
    209             map(vector, tr_buf, input_length, output, output_length);
    210         }
    211         for (i = 0; i < input_length; i++)
    212             invec[(unsigned char)tr_buf[i]] = TRUE;
    213         for (i = 0; i < output_length; i++)
    214             outvec[output[i]] = TRUE;
    215     }
    216 
     267        /*invec[i] = outvec[i] = FALSE; - done by xzalloc */
     268    }
     269
     270    /* -C/-c difference is that -C complements "characters",
     271     * and -c complements "values" (binary bytes I guess).
     272     * In POSIX locale, these are the same.
     273     */
     274
     275    opt_complementary = "-1";
     276    opts = getopt32(argv, "+Ccds"); /* '+': stop at first non-option */
     277    argv += optind;
     278
     279    str1_length = expand(*argv++, &str1);
     280    str2_length = 0;
     281    if (opts & TR_OPT_complement)
     282        str1_length = complement(str1, str1_length);
     283    if (*argv) {
     284        if (argv[0][0] == '\0')
     285            bb_error_msg_and_die("STRING2 cannot be empty");
     286        str2_length = expand(*argv, &str2);
     287        map(vector, str1, str1_length,
     288                str2, str2_length);
     289    }
     290    for (i = 0; i < str1_length; i++)
     291        invec[(unsigned char)(str1[i])] = TRUE;
     292    for (i = 0; i < str2_length; i++)
     293        outvec[(unsigned char)(str2[i])] = TRUE;
     294
     295    goto start_from;
     296
     297    /* In this loop, str1 space is reused as input buffer,
     298     * str2 - as output one. */
    217299    for (;;) {
    218300        /* If we're out of input, flush output and read more input. */
    219         if (in_index == read_chars) {
     301        if ((ssize_t)in_index == read_chars) {
    220302            if (out_index) {
    221                 xwrite(STDOUT_FILENO, (char *)output, out_index);
     303                xwrite(STDOUT_FILENO, str2, out_index);
     304 start_from:
    222305                out_index = 0;
    223306            }
    224             read_chars = read(STDIN_FILENO, tr_buf, BUFSIZ);
     307            read_chars = safe_read(STDIN_FILENO, str1, TR_BUFSIZ);
    225308            if (read_chars <= 0) {
    226                 if (write(STDOUT_FILENO, (char *)output, out_index) != out_index)
    227                     bb_perror_msg(bb_msg_write_error);
    228                 exit(EXIT_SUCCESS);
     309                if (read_chars < 0)
     310                    bb_perror_msg_and_die(bb_msg_read_error);
     311                break;
    229312            }
    230313            in_index = 0;
    231314        }
    232         c = tr_buf[in_index++];
     315        c = str1[in_index++];
     316        if ((opts & TR_OPT_delete) && invec[c])
     317            continue;
    233318        coded = vector[c];
    234         if ((flags & TR_OPT_delete) && invec[c])
     319        if ((opts & TR_OPT_squeeze_reps) && last == coded
     320         && (invec[c] || outvec[coded])
     321        ) {
    235322            continue;
    236         if ((flags & TR_OPT_squeeze_reps) && last == coded &&
    237             (invec[c] || outvec[coded]))
    238             continue;
    239         output[out_index++] = last = coded;
    240     }
    241     /* NOTREACHED */
     323        }
     324        str2[out_index++] = last = coded;
     325    }
     326
    242327    return EXIT_SUCCESS;
    243328}
Note: See TracChangeset for help on using the changeset viewer.