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/util-linux/getopt.c

    r821 r1765  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * getopt.c - Enhanced implementation of BSD getopt(1)
     
    3132 */
    3233
    33 #include <stdio.h>
    34 #include <stdlib.h>
    35 #include <string.h>
    36 #include <unistd.h>
    37 #include <ctype.h>
    3834#include <getopt.h>
    39 
    40 #include "busybox.h"
     35#include "libbb.h"
    4136
    4237/* NON_OPT is the code that is returned when a non-option is found in '+'
     
    4439enum {
    4540    NON_OPT = 1,
     41#if ENABLE_GETOPT_LONG
    4642/* LONG_OPT is the code that is returned when a long option is found. */
    4743    LONG_OPT = 2
     44#endif
    4845};
    4946
    50 /* The shells recognized. */
    51 typedef enum {BASH,TCSH} shell_t;
    52 
    53 
    54 /* Some global variables that tells us how to parse. */
    55 static shell_t shell=BASH; /* The shell we generate output for. */
    56 static int quiet_errors; /* 0 is not quiet. */
    57 static int quiet_output; /* 0 is not quiet. */
    58 static int quote=1; /* 1 is do quote. */
    59 static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */
    60 
    61 /* Function prototypes */
    62 static const char *normalize(const char *arg);
    63 static int generate_output(char * argv[],int argc,const char *optstr,
    64             const struct option *longopts);
    65 static void add_long_options(char *options);
    66 static void add_longopt(const char *name,int has_arg);
    67 static void set_shell(const char *new_shell);
    68 
     47/* For finding activated option flags. Must match getopt32 call! */
     48enum {
     49    OPT_o   = 0x1,  // -o
     50    OPT_n   = 0x2,  // -n
     51    OPT_q   = 0x4,  // -q
     52    OPT_Q   = 0x8,  // -Q
     53    OPT_s   = 0x10, // -s
     54    OPT_T   = 0x20, // -T
     55    OPT_u   = 0x40, // -u
     56#if ENABLE_GETOPT_LONG
     57    OPT_a   = 0x80, // -a
     58    OPT_l   = 0x100, // -l
     59#endif
     60    SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
     61};
     62
     63/* 0 is getopt_long, 1 is getopt_long_only */
     64#define alternative  (option_mask32 & OPT_a)
     65
     66#define quiet_errors (option_mask32 & OPT_q)
     67#define quiet_output (option_mask32 & OPT_Q)
     68#define quote        (!(option_mask32 & OPT_u))
     69#define shell_TCSH   (option_mask32 & SHELL_IS_TCSH)
    6970
    7071/*
     
    7778 * each call.
    7879 */
    79 const char *normalize(const char *arg)
    80 {
    81     static char *BUFFER=NULL;
    82     const char *argptr=arg;
     80static const char *normalize(const char *arg)
     81{
    8382    char *bufptr;
    84 
     83#if ENABLE_FEATURE_CLEAN_UP
     84    static char *BUFFER = NULL;
    8585    free(BUFFER);
     86#else
     87    char *BUFFER;
     88#endif
    8689
    8790    if (!quote) { /* Just copy arg */
    88            BUFFER=bb_xstrdup(arg);
     91        BUFFER = xstrdup(arg);
    8992        return BUFFER;
    9093    }
     
    9497       opening quote! We need also the global opening and closing quote,
    9598       and one extra character for '\0'. */
    96     BUFFER=xmalloc(strlen(arg)*4+3);
    97 
    98     bufptr=BUFFER;
    99     *bufptr++='\'';
    100 
    101     while (*argptr) {
    102         if (*argptr == '\'') {
     99    BUFFER = xmalloc(strlen(arg)*4 + 3);
     100
     101    bufptr = BUFFER;
     102    *bufptr ++= '\'';
     103
     104    while (*arg) {
     105        if (*arg == '\'') {
    103106            /* Quote: replace it with: '\'' */
    104             *bufptr++='\'';
    105             *bufptr++='\\';
    106             *bufptr++='\'';
    107             *bufptr++='\'';
    108         } else if (shell==TCSH && *argptr=='!') {
     107            *bufptr ++= '\'';
     108            *bufptr ++= '\\';
     109            *bufptr ++= '\'';
     110            *bufptr ++= '\'';
     111        } else if (shell_TCSH && *arg == '!') {
    109112            /* Exclamation mark: replace it with: \! */
    110             *bufptr++='\'';
    111             *bufptr++='\\';
    112             *bufptr++='!';
    113             *bufptr++='\'';
    114         } else if (shell==TCSH && *argptr=='\n') {
     113            *bufptr ++= '\'';
     114            *bufptr ++= '\\';
     115            *bufptr ++= '!';
     116            *bufptr ++= '\'';
     117        } else if (shell_TCSH && *arg == '\n') {
    115118            /* Newline: replace it with: \n */
    116             *bufptr++='\\';
    117             *bufptr++='n';
    118         } else if (shell==TCSH && isspace(*argptr)) {
     119            *bufptr ++= '\\';
     120            *bufptr ++= 'n';
     121        } else if (shell_TCSH && isspace(*arg)) {
    119122            /* Non-newline whitespace: replace it with \<ws> */
    120             *bufptr++='\'';
    121             *bufptr++='\\';
    122             *bufptr++=*argptr;
    123             *bufptr++='\'';
     123            *bufptr ++= '\'';
     124            *bufptr ++= '\\';
     125            *bufptr ++= *arg;
     126            *bufptr ++= '\'';
    124127        } else
    125128            /* Just copy */
    126             *bufptr++=*argptr;
    127         argptr++;
    128     }
    129     *bufptr++='\'';
    130     *bufptr++='\0';
     129            *bufptr ++= *arg;
     130        arg++;
     131    }
     132    *bufptr ++= '\'';
     133    *bufptr ++= '\0';
    131134    return BUFFER;
    132135}
     
    139142 * Other settings are found in global variables.
    140143 */
    141 int generate_output(char * argv[],int argc,const char *optstr,
    142             const struct option *longopts)
     144#if !ENABLE_GETOPT_LONG
     145#define generate_output(argv,argc,optstr,longopts) generate_output(argv,argc,optstr)
     146#endif
     147static int generate_output(char **argv, int argc, const char *optstr, const struct option *longopts)
    143148{
    144149    int exit_code = 0; /* We assume everything will be OK */
    145     int opt;
     150    unsigned opt;
     151#if ENABLE_GETOPT_LONG
    146152    int longindex;
     153#endif
    147154    const char *charptr;
    148155
    149156    if (quiet_errors) /* No error reporting from getopt(3) */
    150         opterr=0;
    151     optind=0; /* Reset getopt(3) */
    152 
    153     while ((opt = (alternative?
    154                getopt_long_only(argc,argv,optstr,longopts,&longindex):
    155                getopt_long(argc,argv,optstr,longopts,&longindex)))
    156            != EOF)
     157        opterr = 0;
     158    optind = 0; /* Reset getopt(3) */
     159
     160    while (1) {
     161        opt =
     162#if ENABLE_GETOPT_LONG
     163            alternative ?
     164            getopt_long_only(argc, argv, optstr, longopts, &longindex) :
     165            getopt_long(argc, argv, optstr, longopts, &longindex);
     166#else
     167            getopt(argc, argv, optstr);
     168#endif
     169        if (opt == EOF)
     170            break;
    157171        if (opt == '?' || opt == ':' )
    158172            exit_code = 1;
    159173        else if (!quiet_output) {
     174#if ENABLE_GETOPT_LONG
    160175            if (opt == LONG_OPT) {
    161                 printf(" --%s",longopts[longindex].name);
     176                printf(" --%s", longopts[longindex].name);
    162177                if (longopts[longindex].has_arg)
    163178                    printf(" %s",
    164                            normalize(optarg?optarg:""));
    165             } else if (opt == NON_OPT)
    166                 printf(" %s",normalize(optarg));
     179                        normalize(optarg ? optarg : ""));
     180            } else
     181#endif
     182            if (opt == NON_OPT)
     183                printf(" %s", normalize(optarg));
    167184            else {
    168                 printf(" -%c",opt);
     185                printf(" -%c", opt);
    169186                charptr = strchr(optstr,opt);
    170187                if (charptr != NULL && *++charptr == ':')
    171188                    printf(" %s",
    172                            normalize(optarg?optarg:""));
     189                        normalize(optarg ? optarg : ""));
    173190            }
    174191        }
    175 
    176     if (! quiet_output) {
     192    }
     193
     194    if (!quiet_output) {
    177195        printf(" --");
    178196        while (optind < argc)
    179             printf(" %s",normalize(argv[optind++]));
    180         printf("\n");
     197            printf(" %s", normalize(argv[optind++]));
     198        puts("");
    181199    }
    182200    return exit_code;
    183201}
    184202
    185 static struct option *long_options;
    186 static int long_options_length; /* Length of array */
    187 static int long_options_nr; /* Nr of used elements in array */
    188 enum { LONG_OPTIONS_INCR = 10 };
    189 #define init_longopt() add_longopt(NULL,0)
    190 
    191 /* Register a long option. The contents of name is copied. */
    192 void add_longopt(const char *name,int has_arg)
    193 {
    194     if (!name) { /* init */
    195         free(long_options);
    196         long_options=NULL;
    197         long_options_length=0;
    198         long_options_nr=0;
    199     }
    200 
    201     if (long_options_nr == long_options_length) {
    202         long_options_length += LONG_OPTIONS_INCR;
    203         long_options=xrealloc(long_options,
    204                      sizeof(struct option) *
    205                      long_options_length);
    206     }
    207 
    208     long_options[long_options_nr].name=NULL;
    209     long_options[long_options_nr].has_arg=0;
    210     long_options[long_options_nr].flag=NULL;
    211     long_options[long_options_nr].val=0;
    212 
    213     if (long_options_nr) { /* Not for init! */
    214         long_options[long_options_nr-1].has_arg=has_arg;
    215         long_options[long_options_nr-1].flag=NULL;
    216         long_options[long_options_nr-1].val=LONG_OPT;
    217            long_options[long_options_nr-1].name=bb_xstrdup(name);
    218     }
    219     long_options_nr++;
    220 }
    221 
    222 
     203#if ENABLE_GETOPT_LONG
    223204/*
    224205 * Register several long options. options is a string of long options,
     
    226207 * This nukes options!
    227208 */
    228 void add_long_options(char *options)
    229 {
     209static struct option *add_long_options(struct option *long_options, char *options)
     210{
     211    int long_nr = 0;
    230212    int arg_opt, tlen;
    231     char *tokptr=strtok(options,", \t\n");
     213    char *tokptr = strtok(options, ", \t\n");
     214
     215    if (long_options)
     216        while (long_options[long_nr].name)
     217            long_nr++;
     218
    232219    while (tokptr) {
    233         arg_opt=no_argument;
    234         tlen=strlen(tokptr);
    235         if (tlen > 0) {
    236             if (tokptr[tlen-1] == ':') {
    237                 if (tlen > 1 && tokptr[tlen-2] == ':') {
    238                     tokptr[tlen-2]='\0';
    239                     tlen -= 2;
    240                     arg_opt=optional_argument;
    241                 } else {
    242                     tokptr[tlen-1]='\0';
    243                     tlen -= 1;
    244                     arg_opt=required_argument;
     220        arg_opt = no_argument;
     221        tlen = strlen(tokptr);
     222        if (tlen) {
     223            tlen--;
     224            if (tokptr[tlen] == ':') {
     225                arg_opt = required_argument;
     226                if (tlen && tokptr[tlen-1] == ':') {
     227                    tlen--;
     228                    arg_opt = optional_argument;
    245229                }
     230                tokptr[tlen] = '\0';
    246231                if (tlen == 0)
    247                     bb_error_msg("empty long option after -l or --long argument");
     232                    bb_error_msg_and_die("empty long option specified");
    248233            }
    249             add_longopt(tokptr,arg_opt);
     234            long_options = xrealloc(long_options,
     235                    sizeof(long_options[0]) * (long_nr+2));
     236            long_options[long_nr].has_arg = arg_opt;
     237            long_options[long_nr].flag = NULL;
     238            long_options[long_nr].val = LONG_OPT;
     239            long_options[long_nr].name = xstrdup(tokptr);
     240            long_nr++;
     241            memset(&long_options[long_nr], 0, sizeof(long_options[0]));
    250242        }
    251         tokptr=strtok(NULL,", \t\n");
    252     }
    253 }
    254 
    255 void set_shell(const char *new_shell)
    256 {
    257     if (!strcmp(new_shell,"bash"))
    258         shell=BASH;
    259     else if (!strcmp(new_shell,"tcsh"))
    260         shell=TCSH;
    261     else if (!strcmp(new_shell,"sh"))
    262         shell=BASH;
    263     else if (!strcmp(new_shell,"csh"))
    264         shell=TCSH;
     243        tokptr = strtok(NULL, ", \t\n");
     244    }
     245    return long_options;
     246}
     247#endif
     248
     249static void set_shell(const char *new_shell)
     250{
     251    if (!strcmp(new_shell,"bash") || !strcmp(new_shell,"sh"))
     252        return;
     253    if (!strcmp(new_shell,"tcsh") || !strcmp(new_shell,"csh"))
     254        option_mask32 |= SHELL_IS_TCSH;
    265255    else
    266         bb_error_msg("unknown shell after -s or --shell argument");
     256        bb_error_msg("unknown shell '%s', assuming bash", new_shell);
    267257}
    268258
     
    276266 */
    277267
    278 static const struct option longopts[]=
    279 {
    280     {"options",required_argument,NULL,'o'},
    281     {"longoptions",required_argument,NULL,'l'},
    282     {"quiet",no_argument,NULL,'q'},
    283     {"quiet-output",no_argument,NULL,'Q'},
    284     {"shell",required_argument,NULL,'s'},
    285     {"test",no_argument,NULL,'T'},
    286     {"unquoted",no_argument,NULL,'u'},
    287     {"alternative",no_argument,NULL,'a'},
    288     {"name",required_argument,NULL,'n'},
    289     {NULL,0,NULL,0}
    290 };
    291 
    292 /* Stop scanning as soon as a non-option argument is found! */
    293 static const char shortopts[]="+ao:l:n:qQs:Tu";
    294 
    295 
     268#if ENABLE_GETOPT_LONG
     269static const char getopt_longopts[] ALIGN1 =
     270    "options\0"      Required_argument "o"
     271    "longoptions\0"  Required_argument "l"
     272    "quiet\0"        No_argument       "q"
     273    "quiet-output\0" No_argument       "Q"
     274    "shell\0"        Required_argument "s"
     275    "test\0"         No_argument       "T"
     276    "unquoted\0"     No_argument       "u"
     277    "alternative\0"  No_argument       "a"
     278    "name\0"         Required_argument "n"
     279    ;
     280#endif
     281
     282int getopt_main(int argc, char *argv[]);
    296283int getopt_main(int argc, char *argv[])
    297284{
    298     const char *optstr = NULL;
     285    char *optstr = NULL;
    299286    char *name = NULL;
    300     int opt;
    301     int compatible=0;
    302 
    303     init_longopt();
    304 
    305     if (getenv("GETOPT_COMPATIBLE"))
    306         compatible=1;
     287    unsigned opt;
     288    const char *compatible;
     289    char *s_arg;
     290#if ENABLE_GETOPT_LONG
     291    struct option *long_options = NULL;
     292    llist_t *l_arg = NULL;
     293#endif
     294
     295    compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
    307296
    308297    if (argc == 1) {
     
    311300               when there were no arguments. */
    312301            printf(" --\n");
    313                return 0;
    314         } else
    315             bb_error_msg_and_die("missing optstring argument");
     302            return 0;
     303        }
     304        bb_error_msg_and_die("missing optstring argument");
    316305    }
    317306
     
    319308        char *s;
    320309
    321         quote=0;
    322         s=xmalloc(strlen(argv[1])+1);
    323         strcpy(s,argv[1]+strspn(argv[1],"-+"));
    324         argv[1]=argv[0];
    325            return (generate_output(argv+1,argc-1,s,long_options));
    326     }
    327 
    328     while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
    329         switch (opt) {
    330         case 'a':
    331             alternative=1;
    332             break;
    333         case 'o':
    334                optstr = optarg;
    335             break;
    336         case 'l':
    337             add_long_options(optarg);
    338             break;
    339         case 'n':
    340                name = optarg;
    341             break;
    342         case 'q':
    343             quiet_errors=1;
    344             break;
    345         case 'Q':
    346             quiet_output=1;
    347             break;
    348         case 's':
    349             set_shell(optarg);
    350             break;
    351         case 'T':
    352                return 4;
    353         case 'u':
    354             quote=0;
    355             break;
    356         default:
    357             bb_show_usage();
    358         }
    359 
     310        option_mask32 |= OPT_u; /* quoting off */
     311        s = xstrdup(argv[1] + strspn(argv[1], "-+"));
     312        argv[1] = argv[0];
     313        return generate_output(argv+1, argc-1, s, long_options);
     314    }
     315
     316#if !ENABLE_GETOPT_LONG
     317    opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
     318#else
     319    applet_long_options = getopt_longopts;
     320    opt_complementary = "l::";
     321    opt = getopt32(argv, "+o:n:qQs:Tual:",
     322                    &optstr, &name, &s_arg, &l_arg);
     323    /* Effectuate the read options for the applet itself */
     324    while (l_arg) {
     325        long_options = add_long_options(long_options, l_arg->data);
     326        l_arg = l_arg->link;
     327    }
     328#endif
     329
     330    if (opt & OPT_s) {
     331        set_shell(s_arg);
     332    }
     333
     334    if (opt & OPT_T) {
     335        return 4;
     336    }
     337
     338    /* All options controlling the applet have now been parsed */
    360339    if (!optstr) {
    361340        if (optind >= argc)
    362341            bb_error_msg_and_die("missing optstring argument");
    363         else optstr=argv[optind++];
    364     }
    365     if (name)
    366         argv[optind-1]=name;
    367     else
    368         argv[optind-1]=argv[0];
    369        return (generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
    370 }
     342        optstr = argv[optind++];
     343    }
     344
     345    argv[optind-1] = name ? name : argv[0];
     346    return generate_output(argv+optind-1, argc-optind+1, optstr, long_options);
     347}
Note: See TracChangeset for help on using the changeset viewer.