Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/util-linux/getopt.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/util-linux/getopt.c
r821 r1770 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * getopt.c - Enhanced implementation of BSD getopt(1) … … 31 32 */ 32 33 33 #include <stdio.h>34 #include <stdlib.h>35 #include <string.h>36 #include <unistd.h>37 #include <ctype.h>38 34 #include <getopt.h> 39 40 #include "busybox.h" 35 #include "libbb.h" 41 36 42 37 /* NON_OPT is the code that is returned when a non-option is found in '+' … … 44 39 enum { 45 40 NON_OPT = 1, 41 #if ENABLE_GETOPT_LONG 46 42 /* LONG_OPT is the code that is returned when a long option is found. */ 47 43 LONG_OPT = 2 44 #endif 48 45 }; 49 46 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! */ 48 enum { 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) 69 70 70 71 /* … … 77 78 * each call. 78 79 */ 79 const char *normalize(const char *arg) 80 { 81 static char *BUFFER=NULL; 82 const char *argptr=arg; 80 static const char *normalize(const char *arg) 81 { 83 82 char *bufptr; 84 83 #if ENABLE_FEATURE_CLEAN_UP 84 static char *BUFFER = NULL; 85 85 free(BUFFER); 86 #else 87 char *BUFFER; 88 #endif 86 89 87 90 if (!quote) { /* Just copy arg */ 88 BUFFER=bb_xstrdup(arg);91 BUFFER = xstrdup(arg); 89 92 return BUFFER; 90 93 } … … 94 97 opening quote! We need also the global opening and closing quote, 95 98 and one extra character for '\0'. */ 96 BUFFER =xmalloc(strlen(arg)*4+3);97 98 bufptr =BUFFER;99 *bufptr ++='\'';100 101 while (*arg ptr) {102 if (*arg ptr== '\'') {99 BUFFER = xmalloc(strlen(arg)*4 + 3); 100 101 bufptr = BUFFER; 102 *bufptr ++= '\''; 103 104 while (*arg) { 105 if (*arg == '\'') { 103 106 /* 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 == '!') { 109 112 /* 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') { 115 118 /* 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)) { 119 122 /* 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 ++= '\''; 124 127 } else 125 128 /* Just copy */ 126 *bufptr ++=*argptr;127 arg ptr++;128 } 129 *bufptr ++='\'';130 *bufptr ++='\0';129 *bufptr ++= *arg; 130 arg++; 131 } 132 *bufptr ++= '\''; 133 *bufptr ++= '\0'; 131 134 return BUFFER; 132 135 } … … 139 142 * Other settings are found in global variables. 140 143 */ 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 147 static int generate_output(char **argv, int argc, const char *optstr, const struct option *longopts) 143 148 { 144 149 int exit_code = 0; /* We assume everything will be OK */ 145 int opt; 150 unsigned opt; 151 #if ENABLE_GETOPT_LONG 146 152 int longindex; 153 #endif 147 154 const char *charptr; 148 155 149 156 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; 157 171 if (opt == '?' || opt == ':' ) 158 172 exit_code = 1; 159 173 else if (!quiet_output) { 174 #if ENABLE_GETOPT_LONG 160 175 if (opt == LONG_OPT) { 161 printf(" --%s", longopts[longindex].name);176 printf(" --%s", longopts[longindex].name); 162 177 if (longopts[longindex].has_arg) 163 178 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)); 167 184 else { 168 printf(" -%c", opt);185 printf(" -%c", opt); 169 186 charptr = strchr(optstr,opt); 170 187 if (charptr != NULL && *++charptr == ':') 171 188 printf(" %s", 172 normalize(optarg?optarg:""));189 normalize(optarg ? optarg : "")); 173 190 } 174 191 } 175 176 if (! quiet_output) { 192 } 193 194 if (!quiet_output) { 177 195 printf(" --"); 178 196 while (optind < argc) 179 printf(" %s", normalize(argv[optind++]));180 p rintf("\n");197 printf(" %s", normalize(argv[optind++])); 198 puts(""); 181 199 } 182 200 return exit_code; 183 201 } 184 202 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 223 204 /* 224 205 * Register several long options. options is a string of long options, … … 226 207 * This nukes options! 227 208 */ 228 void add_long_options(char *options) 229 { 209 static struct option *add_long_options(struct option *long_options, char *options) 210 { 211 int long_nr = 0; 230 212 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 232 219 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; 245 229 } 230 tokptr[tlen] = '\0'; 246 231 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"); 248 233 } 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])); 250 242 } 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 249 static 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; 265 255 else 266 bb_error_msg("unknown shell after -s or --shell argument");256 bb_error_msg("unknown shell '%s', assuming bash", new_shell); 267 257 } 268 258 … … 276 266 */ 277 267 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 269 static 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 282 int getopt_main(int argc, char *argv[]); 296 283 int getopt_main(int argc, char *argv[]) 297 284 { 298 c onst char *optstr = NULL;285 char *optstr = NULL; 299 286 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 */ 307 296 308 297 if (argc == 1) { … … 311 300 when there were no arguments. */ 312 301 printf(" --\n"); 313 314 } else315 302 return 0; 303 } 304 bb_error_msg_and_die("missing optstring argument"); 316 305 } 317 306 … … 319 308 char *s; 320 309 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 */ 360 339 if (!optstr) { 361 340 if (optind >= argc) 362 341 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.