1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME 80** 81** GETFLAGS.C 82** 83** FACILITY: 84** 85** Interface Definition Language (IDL) Compiler 86** 87** ABSTRACT: 88** 89** Command Line Parser 90** 91** VERSION: DCE 1.0 92** 93*/ 94 95#include <ctype.h> 96 97#include <nidl.h> 98#include <getflags.h> 99#include <command.h> 100#include <driver.h> 101#include <message.h> 102 103#define NFLAGS 128 104static unsigned char option_count[NFLAGS] = {0}; 105static int other_count = 0; 106static char *(other_flags[NFLAGS]) = {0}; 107 108char *last_string; /* Last string parsed, for disambiguating */ 109 110/* 111 * flags_option_count: Returns #occurences of option on command line. 112 */ 113int flags_option_count 114( 115 const OPTIONS table[], 116 const char *option 117) 118{ 119 int o; 120 121 if (*option == '-') 122 option++; 123 for (o = 0; table[o].option && o < NFLAGS; o++) 124 { 125 if (strcmp(option, table[o].option) == 0) 126 return((int)option_count[o]); 127 } 128 return(-1); 129} 130 131/* 132 * flags_incr_count: Increments command option count by specified amount. 133 */ 134void flags_incr_count 135( 136 const OPTIONS table[], 137 const char *option, 138 int delta 139) 140{ 141 int o; 142 143 if (*option == '-') 144 option++; 145 for (o = 0; table[o].option && o < NFLAGS; o++) 146 { 147 if (strlen(option) != strlen(table[o].option)) 148 continue; 149 if (strcmp(option, table[o].option) == 0) 150 { 151 option_count[o] += delta; 152 return; 153 } 154 } 155} 156 157/* 158 * flags_other_count: Returns count of command line parameters that are not 159 * part of command line options. 160 */ 161int flags_other_count 162( 163 void 164) 165{ 166 return(other_count); 167} 168 169/* 170 * flags_other: Returns the Nth command line parameter that is not an option. 171 */ 172char *flags_other 173( 174 int index 175) 176{ 177 if (0 <= index && index < other_count) 178 return(other_flags[index]); 179 else 180 return(NULL); 181} 182 183/* 184 * is_number: Returns true if argument consists only of ASCII "0" thru "9" 185 * with optional leading "+" or "-". 186 */ 187 188boolean is_number 189( 190 char *str 191) 192{ 193 if (*str == '+' || *str == '-') 194 str++; 195 196 for ( ; *str != '\0' ; str++) 197 if (!isdigit((int)*str)) 198 return false; 199 200 return true; 201} 202 203/* 204 * getflags: Parses command parameters and options. 205 */ 206void getflags 207( 208 int ac, 209 char **av, 210 const OPTIONS table[] 211) 212{ 213 int o; 214 int optlen; 215 int nflags, type; 216 int vflag; 217 boolean optval; 218 register char **pstring; 219 register char *pchar; 220 register int *pint; 221 register char *flag = NULL; 222 register long *plong; 223 register double *pfloat; 224 225 last_string = NULL; 226 227 while (ac > 0) 228 { 229 thisf: 230 for (o = 0; table[o].option; o++) 231 { 232 flag = *av; 233 if (flag[0] == '-') 234 flag++; 235 236 if (strlen(flag) != strlen(table[o].option)) 237 continue; 238 239 if (strcmp(flag, table[o].option) == 0) 240 { 241 optval = false; /* This is not OptVal with no white space */ 242 matchf: 243 nflags = (table[o].ftype >> 8) & 0xFF; 244 vflag = nflags & VARARGFLAG; 245 nflags &= MULTARGMASK; 246 if (nflags <= 0) 247 nflags = 1; 248 type = table[o].ftype & 0xFF; 249 250 switch (type) 251 { 252 default: 253 INTERNAL_ERROR("Illegal option type"); 254 255 case INTARG: 256 pint = (int *)table[o].dest; 257 if (vflag) 258 pint += option_count[o]; 259 /* 260 * Replacing "if (nflags" with "while (nflags--" allows 261 * lists such as -bug 1 2, but makes parameter determination 262 * ambiguous. As it stands, -bug 1 -bug 2 must be used. 263 */ 264 if (nflags && (ac > 1)) 265 { 266 if (is_number(av[1])) 267 { 268 GETINT(*pint++); 269 } 270 else 271 goto nextf; 272 if (ac > 0 && vflag && **av == '-') goto thisf; 273 option_count[o]++; 274 } 275 goto nextf; 276 277 case STRARG: 278 pstring = (char **)table[o].dest; 279 280 if (vflag) 281 pstring += option_count[o]; 282 /* 283 * Do the following statement even if no more values on the 284 * command line, so caller can later determine, if desired, 285 * that a required value was not supplied (option_count[o] 286 * != 0 but option value left at caller's initialization. 287 */ 288 option_count[o]++; 289 /* 290 * Replacing "if (nflags" with "while (nflags--" allows 291 * lists like -D foo bar, but makes parameter determination 292 * ambiguous. As it stands, -D foo -D bar must be used. 293 */ 294 if (nflags && (ac > 1)) 295 { 296 GETSTR(*pstring); 297 if (ac > 0 && vflag && **av == '-') 298 { 299 *pstring = NULL; 300 goto thisf; 301 } 302 /** Add pstring++; for while loop version **/ 303 } 304 goto nextf; 305 306 case OSTRARG: 307 /* Similar to STRARG, but allows for optional string arg. */ 308 pstring = (char **)table[o].dest; 309 310 /* 311 * Allow the string argument to be optional. 312 */ 313 if (!optval) 314 { 315 if (ac == 1 || (ac > 1 && *av[1] == '-')) 316 { 317 *pstring = (char*) ""; 318 goto nextf; 319 } 320 } 321 322 if (vflag) 323 pstring += option_count[o]; 324 /* 325 * Replacing "if (nflags" with "while (nflags--" allows 326 * lists like -D foo bar, but makes parameter determination 327 * ambiguous. As it stands, -D foo -D bar must be used. 328 */ 329 if (nflags && (ac > 1)) 330 { 331 GETSTR(*pstring); 332 if (ac > 0 && vflag && **av == '-') 333 { 334 *pstring = NULL; 335 goto thisf; 336 } 337 /* 338 * Save pointer to this string, so caller can use to 339 * disambiguate ambiguous syntax. 340 */ 341 last_string = *pstring; 342 /** Add pstring++; for while loop version **/ 343 option_count[o]++; 344 } 345 goto nextf; 346 347 case TOGGLEARG: 348 pchar = (char *)table[o].dest; 349 *pchar = ~*pchar; 350 goto nextf; 351 352 case ASSERTARG: 353 pchar = (char *)table[o].dest; 354 *pchar = true; 355 goto nextf; 356 357 case DENYARG: 358 pchar = (char *)table[o].dest; 359 *pchar = false; 360 goto nextf; 361 362 case CHRARG: 363 pchar = (char *)table[o].dest; 364 if (vflag) 365 pchar += option_count[o]; 366 /* 367 * Replacing "if (nflags" with "while (nflags--" allows 368 * lists such as -opt a b, but makes parameter determination 369 * ambiguous. As it stands, -opt a -opt b must be used. 370 */ 371 if (nflags && (ac > 1)) 372 { 373 GETCH(*pchar++); 374 if (ac > 0 && vflag && **av == '-') goto thisf; 375 option_count[o]++; 376 } 377 goto nextf; 378 379 case FLTARG: 380 pfloat = (double *)table[o].dest; 381 if (vflag) 382 pfloat += option_count[o]; 383 /* 384 * Replacing "if (nflags" with "while (nflags--" allows 385 * lists like -f 1.1 2.2, but makes parameter determination 386 * ambiguous. As it stands, -f 1.1 -f 2.2 must be used. 387 */ 388 if (nflags && (ac > 1)) 389 { 390 GETFLT(*pfloat++); 391 if (ac > 0 && vflag && **av == '-') goto thisf; 392 option_count[o]++; 393 } 394 goto nextf; 395 396 case LONGARG: 397 plong = (long *)table[o].dest; 398 if (vflag) 399 plong += option_count[o]; 400 /* 401 * Replacing "if (nflags" with "while (nflags--" allows 402 * lists such as -bug 1 2, but makes parameter determination 403 * ambiguous. As it stands, -bug 1 -bug 2 must be used. 404 */ 405 if (nflags && (ac > 1)) 406 { 407 if (is_number(av[1])) 408 { 409 GETLONG(*plong++); 410 } 411 else 412 goto nextf; 413 if (ac > 0 && vflag && **av == '-') goto thisf; 414 option_count[o]++; 415 } 416 goto nextf; 417 } 418 } 419 } 420 421 if (**av == '-') 422 { 423 /* 424 * Check for the case of -OptVal, i.e. where the option name and 425 * its value are not separated by white space. This code isn't 426 * pretty. So horrendous code promotes horrendous code! 427 */ 428 for (o = 0; table[o].option; o++) 429 { 430 optlen = strlen(table[o].option); 431 if (strncmp(flag, table[o].option, optlen) == 0) 432 { 433 /* 434 * If an option that's not supposed to take a value, then 435 * issue error and exit. 436 */ 437 type = table[o].ftype & 0xFF; 438 if (type==TOGGLEARG || type==ASSERTARG || type==DENYARG) 439 { 440 message_print(NIDL_OPTNOVAL, table[o].option); 441 CMD_explain_args(); 442 exit(pgm_error); 443 } 444 445 /* 446 * Modify the argv entry to be just Val instead of -OptVal. 447 */ 448 optval = true; /* Parsed -OptVal with no white space */ 449 *av += optlen+1; /* Point argptr past -Opt part */ 450 /* 451 * Fake out the code above as if -Opt and Val are two 452 * separate entries. In reality, Val is now a separate 453 * entry and -Opt has been destroyed (no longer needed). 454 */ 455 ac++; 456 av--; 457 goto matchf; 458 } 459 } 460 461 /* 462 * Unknown option. 463 */ 464 message_print(NIDL_UNKFLAG, *av); 465 CMD_explain_args(); 466 exit(pgm_error); 467 } 468 else 469 { 470 other_flags[other_count++] = *av; 471 } 472 473 nextf: 474 ac--; 475 av++; 476 } 477} 478 479/* 480 * printflags: Prints list of command options and values to stderr. 481 */ 482 483#define yes_no(x) (x? "Yes" : "No") 484#define no_yes(x) (x? "No" : "Yes") 485 486void printflags 487( 488 const OPTIONS table[] 489) 490{ 491 register int o; 492 register int nflags; 493 register int type; 494 int vflag; 495 int *pint; 496 char *pchar; 497 char **pstring; 498 long *plong; 499 double *pdouble; 500 unsigned int option_len; 501 502 option_len = 0; 503 504 for (o = 0; table[o].option; o++) 505 if (strlen(table[o].option) > option_len) 506 option_len = strlen(table[o].option); 507 508 option_len += 3; 509 510 message_print(NIDL_OPTIONSTABLE); 511 for (o = 0; table[o].option; o++) 512 { 513 type = table[o].ftype; 514 if (type & HIDARG) continue; 515 nflags = (type >> 8) & 0xFF; 516 vflag = nflags & VARARGFLAG; 517 518 if (vflag) 519 nflags = option_count[o]; 520 521 type &= 255; 522 fprintf(stderr, " %-*s", option_len, table[o].option); 523 524 if (!vflag && nflags <= 0) 525 nflags = 1; 526 527 switch (type) 528 { 529 default: 530 fprintf(stderr, "\tillegal option in printflags: %d\n", 531 table[o].ftype); 532 exit(pgm_error); 533 534 case INTARG: 535 pint = (int *)table[o].dest; 536 while (nflags-- > 0) 537 fprintf(stderr, "\t%d", *pint++); 538 fprintf(stderr, "\n"); 539 break; 540 541 case STRARG: 542 case OSTRARG: 543 pstring = (char **)table[o].dest; 544 while (nflags-- > -0) 545 fprintf(stderr, "\t%s", *pstring++); 546 fprintf(stderr, "\n"); 547 break; 548 549 case TOGGLEARG: 550 case ASSERTARG: 551 pchar = (char *)table[o].dest; 552 while (nflags-- > 0) 553 fprintf(stderr, "\t%s", yes_no(*pchar++)); 554 fprintf(stderr, "\n"); 555 break; 556 557 case DENYARG: 558 pchar = (char *)table[o].dest; 559 while (nflags-- > 0) 560 fprintf(stderr, "\t%s", no_yes(*pchar++)); 561 fprintf(stderr, "\n"); 562 break; 563 564 case CHRARG: 565 pchar = (char *)table[o].dest; 566 while (nflags-- > 0) 567 fprintf(stderr, "\t%c", *pchar++); 568 fprintf(stderr, "\n"); 569 break; 570 571 case FLTARG: 572 pdouble = (double *)table[o].dest; 573 while (nflags-- > 0) 574 fprintf(stderr, "\t%.3f", *pdouble++); 575 fprintf(stderr, "\n"); 576 break; 577 578 case LONGARG: 579 plong = (long *)table[o].dest; 580 while (nflags-- > 0) 581 fprintf(stderr, "\t%ld", *plong++); 582 fprintf(stderr, "\n"); 583 break; 584 } 585 } 586 587 fprintf(stderr, "\n"); 588} 589