Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/coreutils/cut.c


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/coreutils/cut.c

    r821 r1765  
    1 /* vi: set sw=8 ts=8: */
     1/* vi: set sw=4 ts=4: */
    22/*
    33 * cut.c - minimalist version of cut
     
    55 * Copyright (C) 1999,2000,2001 by Lineo, inc.
    66 * Written by Mark Whitley <markw@codepoet.org>
     7 * debloated by Bernhard Fischer
    78 *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    16  * General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    21  *
     9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    2210 */
    2311
    24 #include <stdio.h>
    25 #include <stdlib.h>
    26 #include <unistd.h>
    27 #include <string.h>
    28 #include <limits.h>
    29 #include "busybox.h"
     12#include "libbb.h"
     13
     14/* This is a NOEXEC applet. Be very careful! */
    3015
    3116
    3217/* option vars */
    33 static const char optstring[] = "b:c:f:d:sn";
    34 #define OPT_BYTE_FLGS    1
    35 #define OPT_CHAR_FLGS    2
    36 #define OPT_FIELDS_FLGS  4
    37 #define OPT_DELIM_FLGS   8
    38 #define OPT_SUPRESS_FLGS 16
    39 static char part; /* (b)yte, (c)har, (f)ields */
    40 static unsigned int supress_non_delimited_lines;
    41 static char delim = '\t'; /* delimiter, default is tab */
     18static const char optstring[] ALIGN1 = "b:c:f:d:sn";
     19#define CUT_OPT_BYTE_FLGS   (1<<0)
     20#define CUT_OPT_CHAR_FLGS   (1<<1)
     21#define CUT_OPT_FIELDS_FLGS (1<<2)
     22#define CUT_OPT_DELIM_FLGS  (1<<3)
     23#define CUT_OPT_SUPPRESS_FLGS (1<<4)
     24
     25static char delim = '\t';   /* delimiter, default is tab */
    4226
    4327struct cut_list {
     
    5236};
    5337
    54 static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
    55 static unsigned int nlists = 0; /* number of elements in above list */
     38/* growable array holding a series of lists */
     39static struct cut_list *cut_lists;
     40static unsigned int nlists; /* number of elements in above list */
    5641
    5742
    5843static int cmpfunc(const void *a, const void *b)
    5944{
    60     struct cut_list *la = (struct cut_list *)a;
    61     struct cut_list *lb = (struct cut_list *)b;
    62 
    63     if (la->startpos > lb->startpos)
    64         return 1;
    65     if (la->startpos < lb->startpos)
    66         return -1;
    67     return 0;
     45    return (((struct cut_list *) a)->startpos -
     46            ((struct cut_list *) b)->startpos);
     47
    6848}
    6949
    70 
    71 /*
    72  * parse_lists() - parses a list and puts values into startpos and endpos.
    73  * valid list formats: N, N-, N-M, -M
    74  * more than one list can be separated by commas
    75  */
    76 static void parse_lists(char *lists)
    77 {
    78     char *ltok = NULL;
    79     char *ntok = NULL;
    80     char *junk;
    81     int s = 0, e = 0;
    82 
    83     /* take apart the lists, one by one (they are separated with commas */
    84     while ((ltok = strsep(&lists, ",")) != NULL) {
    85 
    86         /* it's actually legal to pass an empty list */
    87         if (strlen(ltok) == 0)
    88             continue;
    89 
    90         /* get the start pos */
    91         ntok = strsep(&ltok, "-");
    92         if (ntok == NULL) {
    93             fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
    94         } else if (strlen(ntok) == 0) {
    95             s = BOL;
    96         } else {
    97             s = strtoul(ntok, &junk, 10);
    98             if(*junk != '\0' || s < 0)
    99                 bb_error_msg_and_die("invalid byte or field list");
    100 
    101             /* account for the fact that arrays are zero based, while the user
    102              * expects the first char on the line to be char # 1 */
    103             if (s != 0)
    104                 s--;
    105         }
    106 
    107         /* get the end pos */
    108         ntok = strsep(&ltok, "-");
    109         if (ntok == NULL) {
    110             e = NON_RANGE;
    111         } else if (strlen(ntok) == 0) {
    112             e = EOL;
    113         } else {
    114             e = strtoul(ntok, &junk, 10);
    115             if(*junk != '\0' || e < 0)
    116                 bb_error_msg_and_die("invalid byte or field list");
    117             /* if the user specified and end position of 0, that means "til the
    118              * end of the line */
    119             if (e == 0)
    120                 e = INT_MAX;
    121             e--; /* again, arrays are zero based, lines are 1 based */
    122             if (e == s)
    123                 e = NON_RANGE;
    124         }
    125 
    126         /* if there's something left to tokenize, the user past an invalid list */
    127         if (ltok)
    128             bb_error_msg_and_die("invalid byte or field list");
    129 
    130         /* add the new list */
    131         cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
    132         cut_lists[nlists-1].startpos = s;
    133         cut_lists[nlists-1].endpos = e;
    134     }
    135 
    136     /* make sure we got some cut positions out of all that */
    137     if (nlists == 0)
    138         bb_error_msg_and_die("missing list of positions");
    139 
    140     /* now that the lists are parsed, we need to sort them to make life easier
    141      * on us when it comes time to print the chars / fields / lines */
    142     qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
    143 
    144 }
    145 
    146 
    147 static void cut_line_by_chars(const char *line)
    148 {
    149     int c, l;
    150     /* set up a list so we can keep track of what's been printed */
    151     char *printed = xcalloc(strlen(line), sizeof(char));
    152 
    153     /* print the chars specified in each cut list */
    154     for (c = 0; c < nlists; c++) {
    155         l = cut_lists[c].startpos;
    156         while (l < strlen(line)) {
    157             if (!printed[l]) {
    158                 putchar(line[l]);
    159                 printed[l] = 'X';
    160             }
    161             l++;
    162             if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
    163                 break;
    164         }
    165     }
    166     putchar('\n'); /* cuz we were handed a chomped line */
    167     free(printed);
    168 }
    169 
    170 
    171 static void cut_line_by_fields(char *line)
    172 {
    173     int c, f;
    174     int ndelim = -1; /* zero-based / one-based problem */
    175     int nfields_printed = 0;
    176     char *field = NULL;
    177     char d[2] = { delim, 0 };
    178     char *printed;
    179 
    180     /* test the easy case first: does this line contain any delimiters? */
    181     if (strchr(line, delim) == NULL) {
    182         if (!supress_non_delimited_lines)
    183             puts(line);
    184         return;
    185     }
    186 
    187     /* set up a list so we can keep track of what's been printed */
    188     printed = xcalloc(strlen(line), sizeof(char));
    189 
    190     /* process each list on this line, for as long as we've got a line to process */
    191     for (c = 0; c < nlists && line; c++) {
    192         f = cut_lists[c].startpos;
    193         do {
    194 
    195             /* find the field we're looking for */
    196             while (line && ndelim < f) {
    197                 field = strsep(&line, d);
    198                 ndelim++;
    199             }
    200 
    201             /* we found it, and it hasn't been printed yet */
    202             if (field && ndelim == f && !printed[ndelim]) {
    203                 /* if this isn't our first time through, we need to print the
    204                  * delimiter after the last field that was printed */
    205                 if (nfields_printed > 0)
    206                     putchar(delim);
    207                 fputs(field, stdout);
    208                 printed[ndelim] = 'X';
    209                 nfields_printed++;
    210             }
    211 
    212             f++;
    213 
    214             /* keep going as long as we have a line to work with, this is a
    215              * list, and we're not at the end of that list */
    216         } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
    217     }
    218 
    219     /* if we printed anything at all, we need to finish it with a newline cuz
    220      * we were handed a chomped line */
    221     putchar('\n');
    222 
    223     free(printed);
    224 }
    225 
    226 
    227 static void cut_file_by_lines(const char *line, unsigned int linenum)
    228 {
    229     static int c = 0;
    230     static int l = -1;
    231 
    232     /* I can't initialize this above cuz the "initializer isn't
    233      * constant" *sigh* */
    234     if (l == -1)
    235         l = cut_lists[c].startpos;
    236 
    237     /* get out if we have no more lists to process or if the lines are lower
    238      * than what we're interested in */
    239     if (c >= nlists || linenum < l)
    240         return;
    241 
    242     /* if the line we're looking for is lower than the one we were passed, it
    243      * means we displayed it already, so move on */
    244     while (l < linenum) {
    245         l++;
    246         /* move on to the next list if we're at the end of this one */
    247         if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
    248             c++;
    249             /* get out if there's no more lists to process */
    250             if (c >= nlists)
    251                 return;
    252             l = cut_lists[c].startpos;
    253             /* get out if the current line is lower than the one we just became
    254              * interested in */
    255             if (linenum < l)
    256                 return;
    257         }
    258     }
    259 
    260     /* If we made it here, it means we've found the line we're looking for, so print it */
    261     puts(line);
    262 }
    263 
    264 
    265 /*
    266  * snippy-snip
    267  */
    268 static void cut_file(FILE *file)
     50static void cut_file(FILE * file)
    26951{
    27052    char *line = NULL;
    271     unsigned int linenum = 0; /* keep these zero-based to be consistent */
     53    unsigned int linenum = 0;   /* keep these zero-based to be consistent */
    27254
    27355    /* go through every line in the file */
    274     while ((line = bb_get_chomped_line_from_file(file)) != NULL) {
     56    while ((line = xmalloc_getline(file)) != NULL) {
     57
     58        /* set up a list so we can keep track of what's been printed */
     59        char * printed = xzalloc(strlen(line) * sizeof(char));
     60        char * orig_line = line;
     61        unsigned int cl_pos = 0;
     62        int spos;
    27563
    27664        /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
    277         if ((part & (OPT_CHAR_FLGS | OPT_BYTE_FLGS)))
    278             cut_line_by_chars(line);
    279 
    280         /* cut based on fields */
    281         else {
    282             if (delim == '\n')
    283                 cut_file_by_lines(line, linenum);
    284             else
    285                 cut_line_by_fields(line);
    286         }
    287 
     65        if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) {
     66            /* print the chars specified in each cut list */
     67            for (; cl_pos < nlists; cl_pos++) {
     68                spos = cut_lists[cl_pos].startpos;
     69                while (spos < strlen(line)) {
     70                    if (!printed[spos]) {
     71                        printed[spos] = 'X';
     72                        putchar(line[spos]);
     73                    }
     74                    spos++;
     75                    if (spos > cut_lists[cl_pos].endpos
     76                        || cut_lists[cl_pos].endpos == NON_RANGE)
     77                        break;
     78                }
     79            }
     80        } else if (delim == '\n') { /* cut by lines */
     81            spos = cut_lists[cl_pos].startpos;
     82
     83            /* get out if we have no more lists to process or if the lines
     84             * are lower than what we're interested in */
     85            if (linenum < spos || cl_pos >= nlists)
     86                goto next_line;
     87
     88            /* if the line we're looking for is lower than the one we were
     89             * passed, it means we displayed it already, so move on */
     90            while (spos < linenum) {
     91                spos++;
     92                /* go to the next list if we're at the end of this one */
     93                if (spos > cut_lists[cl_pos].endpos
     94                    || cut_lists[cl_pos].endpos == NON_RANGE) {
     95                    cl_pos++;
     96                    /* get out if there's no more lists to process */
     97                    if (cl_pos >= nlists)
     98                        goto next_line;
     99                    spos = cut_lists[cl_pos].startpos;
     100                    /* get out if the current line is lower than the one
     101                     * we just became interested in */
     102                    if (linenum < spos)
     103                        goto next_line;
     104                }
     105            }
     106
     107            /* If we made it here, it means we've found the line we're
     108             * looking for, so print it */
     109            puts(line);
     110            goto next_line;
     111        } else {        /* cut by fields */
     112            int ndelim = -1;    /* zero-based / one-based problem */
     113            int nfields_printed = 0;
     114            char *field = NULL;
     115            const char delimiter[2] = { delim, 0 };
     116
     117            /* does this line contain any delimiters? */
     118            if (strchr(line, delim) == NULL) {
     119                if (!(option_mask32 & CUT_OPT_SUPPRESS_FLGS))
     120                    puts(line);
     121                goto next_line;
     122            }
     123
     124            /* process each list on this line, for as long as we've got
     125             * a line to process */
     126            for (; cl_pos < nlists && line; cl_pos++) {
     127                spos = cut_lists[cl_pos].startpos;
     128                do {
     129                    /* find the field we're looking for */
     130                    while (line && ndelim < spos) {
     131                        field = strsep(&line, delimiter);
     132                        ndelim++;
     133                    }
     134
     135                    /* we found it, and it hasn't been printed yet */
     136                    if (field && ndelim == spos && !printed[ndelim]) {
     137                        /* if this isn't our first time through, we need to
     138                         * print the delimiter after the last field that was
     139                         * printed */
     140                        if (nfields_printed > 0)
     141                            putchar(delim);
     142                        fputs(field, stdout);
     143                        printed[ndelim] = 'X';
     144                        nfields_printed++;  /* shouldn't overflow.. */
     145                    }
     146
     147                    spos++;
     148
     149                    /* keep going as long as we have a line to work with,
     150                     * this is a list, and we're not at the end of that
     151                     * list */
     152                } while (spos <= cut_lists[cl_pos].endpos && line
     153                         && cut_lists[cl_pos].endpos != NON_RANGE);
     154            }
     155        }
     156        /* if we printed anything at all, we need to finish it with a
     157         * newline cuz we were handed a chomped line */
     158        putchar('\n');
     159 next_line:
    288160        linenum++;
    289         free(line);
     161        free(printed);
     162        free(orig_line);
    290163    }
    291164}
    292165
    293 
     166static const char _op_on_field[] ALIGN1 = " only when operating on fields";
     167
     168int cut_main(int argc, char **argv);
    294169int cut_main(int argc, char **argv)
    295170{
    296     unsigned long opt;
    297     char *sopt, *sdopt;
    298 
    299     bb_opt_complementally = "b--bcf:c--bcf:f--bcf";
    300     opt = bb_getopt_ulflags(argc, argv, optstring, &sopt, &sopt, &sopt, &sdopt);
    301     part = opt & (OPT_BYTE_FLGS|OPT_CHAR_FLGS|OPT_FIELDS_FLGS);
    302     if(part == 0)
    303         bb_error_msg_and_die("you must specify a list of bytes, characters, or fields");
    304     if(opt & BB_GETOPT_ERROR)
    305         bb_error_msg_and_die("only one type of list may be specified");
    306     parse_lists(sopt);
    307     if((opt & (OPT_DELIM_FLGS))) {
    308         if (strlen(sdopt) > 1) {
     171    char *sopt, *ltok;
     172
     173    opt_complementary = "b--bcf:c--bcf:f--bcf";
     174    getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
     175//  argc -= optind;
     176    argv += optind;
     177    if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
     178        bb_error_msg_and_die("expected a list of bytes, characters, or fields");
     179
     180    if (option_mask32 & CUT_OPT_DELIM_FLGS) {
     181        if (strlen(ltok) > 1) {
    309182            bb_error_msg_and_die("the delimiter must be a single character");
    310183        }
    311         delim = sdopt[0];
    312     }
    313     supress_non_delimited_lines = opt & OPT_SUPRESS_FLGS;
     184        delim = ltok[0];
     185    }
    314186
    315187    /*  non-field (char or byte) cutting has some special handling */
    316     if (part != OPT_FIELDS_FLGS) {
    317         if (supress_non_delimited_lines) {
    318             bb_error_msg_and_die("suppressing non-delimited lines makes sense"
    319                     " only when operating on fields");
     188    if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
     189        if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
     190            bb_error_msg_and_die
     191                ("suppressing non-delimited lines makes sense%s",
     192                 _op_on_field);
    320193        }
    321194        if (delim != '\t') {
    322             bb_error_msg_and_die("a delimiter may be specified only when operating on fields");
    323         }
    324     }
    325 
    326     /* argv[(optind)..(argc-1)] should be names of file to process. If no
     195            bb_error_msg_and_die
     196                ("a delimiter may be specified%s", _op_on_field);
     197        }
     198    }
     199
     200    /*
     201     * parse list and put values into startpos and endpos.
     202     * valid list formats: N, N-, N-M, -M
     203     * more than one list can be separated by commas
     204     */
     205    {
     206        char *ntok;
     207        int s = 0, e = 0;
     208
     209        /* take apart the lists, one by one (they are separated with commas */
     210        while ((ltok = strsep(&sopt, ",")) != NULL) {
     211
     212            /* it's actually legal to pass an empty list */
     213            if (strlen(ltok) == 0)
     214                continue;
     215
     216            /* get the start pos */
     217            ntok = strsep(&ltok, "-");
     218            if (ntok == NULL) {
     219                bb_error_msg
     220                    ("internal error: ntok is null for start pos!?\n");
     221            } else if (strlen(ntok) == 0) {
     222                s = BOL;
     223            } else {
     224                s = xatoi_u(ntok);
     225                /* account for the fact that arrays are zero based, while
     226                 * the user expects the first char on the line to be char #1 */
     227                if (s != 0)
     228                    s--;
     229            }
     230
     231            /* get the end pos */
     232            ntok = strsep(&ltok, "-");
     233            if (ntok == NULL) {
     234                e = NON_RANGE;
     235            } else if (strlen(ntok) == 0) {
     236                e = EOL;
     237            } else {
     238                e = xatoi_u(ntok);
     239                /* if the user specified and end position of 0, that means "til the
     240                 * end of the line */
     241                if (e == 0)
     242                    e = EOL;
     243                e--;    /* again, arrays are zero based, lines are 1 based */
     244                if (e == s)
     245                    e = NON_RANGE;
     246            }
     247
     248            /* if there's something left to tokenize, the user passed
     249             * an invalid list */
     250            if (ltok)
     251                bb_error_msg_and_die("invalid byte or field list");
     252
     253            /* add the new list */
     254            cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
     255            cut_lists[nlists-1].startpos = s;
     256            cut_lists[nlists-1].endpos = e;
     257        }
     258
     259        /* make sure we got some cut positions out of all that */
     260        if (nlists == 0)
     261            bb_error_msg_and_die("missing list of positions");
     262
     263        /* now that the lists are parsed, we need to sort them to make life
     264         * easier on us when it comes time to print the chars / fields / lines
     265         */
     266        qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
     267    }
     268
     269    /* argv[0..argc-1] should be names of file to process. If no
    327270     * files were specified or '-' was specified, take input from stdin.
    328271     * Otherwise, we process all the files specified. */
    329     if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
     272    if (argv[0] == NULL || LONE_DASH(argv[0])) {
    330273        cut_file(stdin);
    331     }
    332     else {
    333         int i;
     274    } else {
    334275        FILE *file;
    335         for (i = optind; i < argc; i++) {
    336             file = bb_wfopen(argv[i], "r");
    337             if(file) {
     276
     277        do {
     278            file = fopen_or_warn(argv[0], "r");
     279            if (file) {
    338280                cut_file(file);
    339281                fclose(file);
    340282            }
    341         }
    342     }
    343 
     283        } while (*++argv);
     284    }
     285    if (ENABLE_FEATURE_CLEAN_UP)
     286        free(cut_lists);
    344287    return EXIT_SUCCESS;
    345288}
Note: See TracChangeset for help on using the changeset viewer.