1 /* 2 * Copyright (C) 1984-2000 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * Process command line options. 14 * 15 * Each option is a single letter which controls a program variable. 16 * The options have defaults which may be changed via 17 * the command line option, toggled via the "-" command, 18 * or queried via the "_" command. 19 */ 20 21 #include "less.h" 22 #include "option.h" 23 24 static struct option *pendopt; 25 public int plusoption = FALSE; 26 27 static char *propt(); 28 static char *optstring(); 29 static int flip_triple(); 30 31 extern int screen_trashed; 32 extern char *every_first_cmd; 33 34 /* 35 * Scan an argument (either from the command line or from the 36 * LESS environment variable) and process it. 37 */ 38 public void 39 scan_option(s) 40 char *s; 41 { 42 register struct option *o; 43 register int optc; 44 char *optname; 45 char *printopt; 46 char *str; 47 int set_default; 48 int lc; 49 int err; 50 PARG parg; 51 52 if (s == NULL) 53 return; 54 55 /* 56 * If we have a pending option which requires an argument, 57 * handle it now. 58 * This happens if the previous option was, for example, "-P" 59 * without a following string. In that case, the current 60 * option is simply the argument for the previous option. 61 */ 62 if (pendopt != NULL) 63 { 64 switch (pendopt->otype & OTYPE) 65 { 66 case STRING: 67 (*pendopt->ofunc)(INIT, s); 68 break; 69 case NUMBER: 70 printopt = propt(pendopt->oletter); 71 *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); 72 break; 73 } 74 pendopt = NULL; 75 return; 76 } 77 78 set_default = FALSE; 79 optname = NULL; 80 81 while (*s != '\0') 82 { 83 /* 84 * Check some special cases first. 85 */ 86 switch (optc = *s++) 87 { 88 case ' ': 89 case '\t': 90 case END_OPTION_STRING: 91 continue; 92 case '-': 93 /* 94 * "--" indicates an option name instead of a letter. 95 */ 96 if (*s == '-') 97 { 98 optname = ++s; 99 break; 100 } 101 /* 102 * "-+" means set these options back to their defaults. 103 * (They may have been set otherwise by previous 104 * options.) 105 */ 106 set_default = (*s == '+'); 107 if (set_default) 108 s++; 109 continue; 110 case '+': 111 /* 112 * An option prefixed by a "+" is ungotten, so 113 * that it is interpreted as less commands 114 * processed at the start of the first input file. 115 * "++" means process the commands at the start of 116 * EVERY input file. 117 */ 118 plusoption = TRUE; 119 if (*s == '+') 120 every_first_cmd = save(++s); 121 else 122 ungetsc(s); 123 s = optstring(s, propt('+')); 124 continue; 125 case '0': case '1': case '2': case '3': case '4': 126 case '5': case '6': case '7': case '8': case '9': 127 /* 128 * Special "more" compatibility form "-<number>" 129 * instead of -z<number> to set the scrolling 130 * window size. 131 */ 132 s--; 133 optc = 'z'; 134 break; 135 } 136 137 /* 138 * Not a special case. 139 * Look up the option letter in the option table. 140 */ 141 err = 0; 142 if (optname == NULL) 143 { 144 printopt = propt(optc); 145 lc = SIMPLE_IS_LOWER(optc); 146 o = findopt(optc); 147 } else 148 { 149 printopt = optname; 150 lc = SIMPLE_IS_LOWER(optname[0]); 151 o = findopt_name(&optname, NULL, &err); 152 s = optname; 153 optname = NULL; 154 if (*s == '\0' || *s == ' ') 155 { 156 /* 157 * The option name matches exactly. 158 */ 159 ; 160 } else if (*s == '=') 161 { 162 /* 163 * The option name is followed by "=value". 164 */ 165 if (o != NULL && 166 (o->otype & OTYPE) != STRING && 167 (o->otype & OTYPE) != NUMBER) 168 { 169 parg.p_string = printopt; 170 error("The %s option should not be followed by =", 171 &parg); 172 quit(QUIT_ERROR); 173 } 174 s++; 175 } else 176 { 177 /* 178 * The specified name is longer than the 179 * real option name. 180 */ 181 o = NULL; 182 } 183 } 184 if (o == NULL) 185 { 186 parg.p_string = printopt; 187 if (err == OPT_AMBIG) 188 error("%s is an ambiguous abbreviation (\"less --help\" for help)", 189 &parg); 190 else 191 error("There is no %s option (\"less --help\" for help)", 192 &parg); 193 quit(QUIT_ERROR); 194 } 195 196 str = NULL; 197 switch (o->otype & OTYPE) 198 { 199 case BOOL: 200 if (set_default) 201 *(o->ovar) = o->odefault; 202 else 203 *(o->ovar) = ! o->odefault; 204 break; 205 case TRIPLE: 206 if (set_default) 207 *(o->ovar) = o->odefault; 208 else 209 *(o->ovar) = flip_triple(o->odefault, lc); 210 break; 211 case STRING: 212 if (*s == '\0') 213 { 214 /* 215 * Set pendopt and return. 216 * We will get the string next time 217 * scan_option is called. 218 */ 219 pendopt = o; 220 return; 221 } 222 /* 223 * Don't do anything here. 224 * All processing of STRING options is done by 225 * the handling function. 226 */ 227 str = s; 228 s = optstring(s, printopt); 229 break; 230 case NUMBER: 231 if (*s == '\0') 232 { 233 pendopt = o; 234 return; 235 } 236 *(o->ovar) = getnum(&s, printopt, (int*)NULL); 237 break; 238 } 239 /* 240 * If the option has a handling function, call it. 241 */ 242 if (o->ofunc != NULL) 243 (*o->ofunc)(INIT, str); 244 } 245 } 246 247 /* 248 * Toggle command line flags from within the program. 249 * Used by the "-" and "_" commands. 250 * how_toggle may be: 251 * OPT_NO_TOGGLE just report the current setting, without changing it. 252 * OPT_TOGGLE invert the current setting 253 * OPT_UNSET set to the default value 254 * OPT_SET set to the inverse of the default value 255 */ 256 public void 257 toggle_option(c, s, how_toggle) 258 int c; 259 char *s; 260 int how_toggle; 261 { 262 register struct option *o; 263 register int num; 264 int no_prompt; 265 int err; 266 PARG parg; 267 268 no_prompt = (how_toggle & OPT_NO_PROMPT); 269 how_toggle &= ~OPT_NO_PROMPT; 270 271 /* 272 * Look up the option letter in the option table. 273 */ 274 o = findopt(c); 275 if (o == NULL) 276 { 277 parg.p_string = propt(c); 278 error("There is no %s option", &parg); 279 return; 280 } 281 282 if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) 283 { 284 parg.p_string = propt(c); 285 error("Cannot change the %s option", &parg); 286 return; 287 } 288 289 if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) 290 { 291 parg.p_string = propt(c); 292 error("Cannot query the %s option", &parg); 293 return; 294 } 295 296 /* 297 * Check for something which appears to be a do_toggle 298 * (because the "-" command was used), but really is not. 299 * This could be a string option with no string, or 300 * a number option with no number. 301 */ 302 switch (o->otype & OTYPE) 303 { 304 case STRING: 305 case NUMBER: 306 if (how_toggle == OPT_TOGGLE && *s == '\0') 307 how_toggle = OPT_NO_TOGGLE; 308 break; 309 } 310 311 #if HILITE_SEARCH 312 if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 313 repaint_hilite(0); 314 #endif 315 316 /* 317 * Now actually toggle (change) the variable. 318 */ 319 if (how_toggle != OPT_NO_TOGGLE) 320 { 321 switch (o->otype & OTYPE) 322 { 323 case BOOL: 324 /* 325 * Boolean. 326 */ 327 switch (how_toggle) 328 { 329 case OPT_TOGGLE: 330 *(o->ovar) = ! *(o->ovar); 331 break; 332 case OPT_UNSET: 333 *(o->ovar) = o->odefault; 334 break; 335 case OPT_SET: 336 *(o->ovar) = ! o->odefault; 337 break; 338 } 339 break; 340 case TRIPLE: 341 /* 342 * Triple: 343 * If user gave the lower case letter, then switch 344 * to 1 unless already 1, in which case make it 0. 345 * If user gave the upper case letter, then switch 346 * to 2 unless already 2, in which case make it 0. 347 */ 348 switch (how_toggle) 349 { 350 case OPT_TOGGLE: 351 *(o->ovar) = flip_triple(*(o->ovar), 352 islower(c)); 353 break; 354 case OPT_UNSET: 355 *(o->ovar) = o->odefault; 356 break; 357 case OPT_SET: 358 *(o->ovar) = flip_triple(o->odefault, 359 islower(c)); 360 break; 361 } 362 break; 363 case STRING: 364 /* 365 * String: don't do anything here. 366 * The handling function will do everything. 367 */ 368 switch (how_toggle) 369 { 370 case OPT_SET: 371 case OPT_UNSET: 372 error("Cannot use \"-+\" or \"--\" for a string option", 373 NULL_PARG); 374 return; 375 } 376 break; 377 case NUMBER: 378 /* 379 * Number: set the variable to the given number. 380 */ 381 switch (how_toggle) 382 { 383 case OPT_TOGGLE: 384 num = getnum(&s, '\0', &err); 385 if (!err) 386 *(o->ovar) = num; 387 break; 388 case OPT_UNSET: 389 *(o->ovar) = o->odefault; 390 break; 391 case OPT_SET: 392 error("Can't use \"-!\" for a numeric option", 393 NULL_PARG); 394 return; 395 } 396 break; 397 } 398 } 399 400 /* 401 * Call the handling function for any special action 402 * specific to this option. 403 */ 404 if (o->ofunc != NULL) 405 (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); 406 407 #if HILITE_SEARCH 408 if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 409 chg_hilite(); 410 #endif 411 412 if (!no_prompt) 413 { 414 /* 415 * Print a message describing the new setting. 416 */ 417 switch (o->otype & OTYPE) 418 { 419 case BOOL: 420 case TRIPLE: 421 /* 422 * Print the odesc message. 423 */ 424 error(o->odesc[*(o->ovar)], NULL_PARG); 425 break; 426 case NUMBER: 427 /* 428 * The message is in odesc[1] and has a %d for 429 * the value of the variable. 430 */ 431 parg.p_int = *(o->ovar); 432 error(o->odesc[1], &parg); 433 break; 434 case STRING: 435 /* 436 * Message was already printed by the handling function. 437 */ 438 break; 439 } 440 } 441 442 if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 443 screen_trashed = TRUE; 444 } 445 446 /* 447 * "Toggle" a triple-valued option. 448 */ 449 static int 450 flip_triple(val, lc) 451 int val; 452 int lc; 453 { 454 if (lc) 455 return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 456 else 457 return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 458 } 459 460 /* 461 * Return a string suitable for printing as the "name" of an option. 462 * For example, if the option letter is 'x', just return "-x". 463 */ 464 static char * 465 propt(c) 466 int c; 467 { 468 static char buf[8]; 469 470 sprintf(buf, "-%s", prchar(c)); 471 return (buf); 472 } 473 474 /* 475 * Determine if an option is a single character option (BOOL or TRIPLE), 476 * or if it a multi-character option (NUMBER). 477 */ 478 public int 479 single_char_option(c) 480 int c; 481 { 482 register struct option *o; 483 484 o = findopt(c); 485 if (o == NULL) 486 return (TRUE); 487 return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0); 488 } 489 490 /* 491 * Return the prompt to be used for a given option letter. 492 * Only string and number valued options have prompts. 493 */ 494 public char * 495 opt_prompt(c) 496 int c; 497 { 498 register struct option *o; 499 500 o = findopt(c); 501 if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 502 return (NULL); 503 return (o->odesc[0]); 504 } 505 506 /* 507 * Return whether or not there is a string option pending; 508 * that is, if the previous option was a string-valued option letter 509 * (like -P) without a following string. 510 * In that case, the current option is taken to be the string for 511 * the previous option. 512 */ 513 public int 514 isoptpending() 515 { 516 return (pendopt != NULL); 517 } 518 519 /* 520 * Print error message about missing string. 521 */ 522 static void 523 nostring(printopt) 524 char *printopt; 525 { 526 PARG parg; 527 parg.p_string = printopt; 528 error("Value is required after %s", &parg); 529 } 530 531 /* 532 * Print error message if a STRING type option is not followed by a string. 533 */ 534 public void 535 nopendopt() 536 { 537 nostring(propt(pendopt->oletter)); 538 } 539 540 /* 541 * Scan to end of string or to an END_OPTION_STRING character. 542 * In the latter case, replace the char with a null char. 543 * Return a pointer to the remainder of the string, if any. 544 */ 545 static char * 546 optstring(s, printopt) 547 char *s; 548 char *printopt; 549 { 550 register char *p; 551 552 if (*s == '\0') 553 { 554 nostring(printopt); 555 quit(QUIT_ERROR); 556 } 557 for (p = s; *p != '\0'; p++) 558 if (*p == END_OPTION_STRING) 559 { 560 *p = '\0'; 561 return (p+1); 562 } 563 return (p); 564 } 565 566 /* 567 * Translate a string into a number. 568 * Like atoi(), but takes a pointer to a char *, and updates 569 * the char * to point after the translated number. 570 */ 571 public int 572 getnum(sp, printopt, errp) 573 char **sp; 574 char *printopt; 575 int *errp; 576 { 577 register char *s; 578 register int n; 579 register int neg; 580 PARG parg; 581 582 s = skipsp(*sp); 583 neg = FALSE; 584 if (*s == '-') 585 { 586 neg = TRUE; 587 s++; 588 } 589 if (*s < '0' || *s > '9') 590 { 591 if (errp != NULL) 592 { 593 *errp = TRUE; 594 return (-1); 595 } 596 parg.p_string = printopt; 597 error("Number is required after %s", &parg); 598 quit(QUIT_ERROR); 599 } 600 601 n = 0; 602 while (*s >= '0' && *s <= '9') 603 n = 10 * n + *s++ - '0'; 604 *sp = s; 605 if (errp != NULL) 606 *errp = FALSE; 607 if (neg) 608 n = -n; 609 return (n); 610 } 611