1 /* 2 * Copyright (C) 1984-2007 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 * Handling functions for command line options. 14 * 15 * Most options are handled by the generic code in option.c. 16 * But all string options, and a few non-string options, require 17 * special handling specific to the particular option. 18 * This special processing is done by the "handling functions" in this file. 19 * 20 * Each handling function is passed a "type" and, if it is a string 21 * option, the string which should be "assigned" to the option. 22 * The type may be one of: 23 * INIT The option is being initialized from the command line. 24 * TOGGLE The option is being changed from within the program. 25 * QUERY The setting of the option is merely being queried. 26 */ 27 28 #include "less.h" 29 #include "option.h" 30 31 extern int nbufs; 32 extern int bufspace; 33 extern int pr_type; 34 extern int plusoption; 35 extern int swindow; 36 extern int sc_height; 37 extern int secure; 38 extern int dohelp; 39 extern int any_display; 40 extern char openquote; 41 extern char closequote; 42 extern char *prproto[]; 43 extern char *eqproto; 44 extern char *hproto; 45 extern char *wproto; 46 extern IFILE curr_ifile; 47 extern char version[]; 48 extern int jump_sline; 49 extern int jump_sline_fraction; 50 extern int less_is_more; 51 #if LOGFILE 52 extern char *namelogfile; 53 extern int force_logfile; 54 extern int logfile; 55 #endif 56 #if TAGS 57 public char *tagoption = NULL; 58 extern char *tags; 59 #endif 60 #if MSDOS_COMPILER 61 extern int nm_fg_color, nm_bg_color; 62 extern int bo_fg_color, bo_bg_color; 63 extern int ul_fg_color, ul_bg_color; 64 extern int so_fg_color, so_bg_color; 65 extern int bl_fg_color, bl_bg_color; 66 #endif 67 68 69 #if LOGFILE 70 /* 71 * Handler for -o option. 72 */ 73 public void 74 opt_o(type, s) 75 int type; 76 char *s; 77 { 78 PARG parg; 79 80 if (secure) 81 { 82 error("log file support is not available", NULL_PARG); 83 return; 84 } 85 switch (type) 86 { 87 case INIT: 88 namelogfile = s; 89 break; 90 case TOGGLE: 91 if (ch_getflags() & CH_CANSEEK) 92 { 93 error("Input is not a pipe", NULL_PARG); 94 return; 95 } 96 if (logfile >= 0) 97 { 98 error("Log file is already in use", NULL_PARG); 99 return; 100 } 101 s = skipsp(s); 102 namelogfile = lglob(s); 103 use_logfile(namelogfile); 104 sync_logfile(); 105 break; 106 case QUERY: 107 if (logfile < 0) 108 error("No log file", NULL_PARG); 109 else 110 { 111 parg.p_string = namelogfile; 112 error("Log file \"%s\"", &parg); 113 } 114 break; 115 } 116 } 117 118 /* 119 * Handler for -O option. 120 */ 121 public void 122 opt__O(type, s) 123 int type; 124 char *s; 125 { 126 force_logfile = TRUE; 127 opt_o(type, s); 128 } 129 #endif 130 131 /* 132 * Handlers for -l option. 133 */ 134 public void 135 opt_l(type, s) 136 int type; 137 char *s; 138 { 139 int err; 140 int n; 141 char *t; 142 143 switch (type) 144 { 145 case INIT: 146 t = s; 147 n = getnum(&t, "l", &err); 148 if (err || n <= 0) 149 { 150 error("Line number is required after -l", NULL_PARG); 151 return; 152 } 153 plusoption = TRUE; 154 ungetsc(s); 155 break; 156 } 157 } 158 159 /* 160 * Handlers for -j option. 161 */ 162 public void 163 opt_j(type, s) 164 int type; 165 char *s; 166 { 167 PARG parg; 168 char buf[16]; 169 int len; 170 int err; 171 172 switch (type) 173 { 174 case INIT: 175 case TOGGLE: 176 if (*s == '.') 177 { 178 s++; 179 jump_sline_fraction = getfraction(&s, "j", &err); 180 if (err) 181 error("Invalid line fraction", NULL_PARG); 182 else 183 calc_jump_sline(); 184 } else 185 { 186 int sline = getnum(&s, "j", &err); 187 if (err) 188 error("Invalid line number", NULL_PARG); 189 else 190 { 191 jump_sline = sline; 192 jump_sline_fraction = -1; 193 } 194 } 195 break; 196 case QUERY: 197 if (jump_sline_fraction < 0) 198 { 199 parg.p_int = jump_sline; 200 error("Position target at screen line %d", &parg); 201 } else 202 { 203 204 sprintf(buf, ".%06d", jump_sline_fraction); 205 len = strlen(buf); 206 while (len > 2 && buf[len-1] == '0') 207 len--; 208 buf[len] = '\0'; 209 parg.p_string = buf; 210 error("Position target at screen position %s", &parg); 211 } 212 break; 213 } 214 } 215 216 public void 217 calc_jump_sline() 218 { 219 if (jump_sline_fraction < 0) 220 return; 221 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM; 222 } 223 224 #if USERFILE 225 public void 226 opt_k(type, s) 227 int type; 228 char *s; 229 { 230 PARG parg; 231 232 switch (type) 233 { 234 case INIT: 235 if (lesskey(s, 0)) 236 { 237 parg.p_string = s; 238 error("Cannot use lesskey file \"%s\"", &parg); 239 } 240 break; 241 } 242 } 243 #endif 244 245 #if TAGS 246 /* 247 * Handler for -t option. 248 */ 249 public void 250 opt_t(type, s) 251 int type; 252 char *s; 253 { 254 IFILE save_ifile; 255 POSITION pos; 256 257 switch (type) 258 { 259 case INIT: 260 tagoption = s; 261 /* Do the rest in main() */ 262 break; 263 case TOGGLE: 264 if (secure) 265 { 266 error("tags support is not available", NULL_PARG); 267 break; 268 } 269 findtag(skipsp(s)); 270 save_ifile = save_curr_ifile(); 271 /* 272 * Try to open the file containing the tag 273 * and search for the tag in that file. 274 */ 275 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 276 { 277 /* Failed: reopen the old file. */ 278 reedit_ifile(save_ifile); 279 break; 280 } 281 unsave_ifile(save_ifile); 282 jump_loc(pos, jump_sline); 283 break; 284 } 285 } 286 287 /* 288 * Handler for -T option. 289 */ 290 public void 291 opt__T(type, s) 292 int type; 293 char *s; 294 { 295 PARG parg; 296 297 switch (type) 298 { 299 case INIT: 300 tags = s; 301 break; 302 case TOGGLE: 303 s = skipsp(s); 304 tags = lglob(s); 305 break; 306 case QUERY: 307 parg.p_string = tags; 308 error("Tags file \"%s\"", &parg); 309 break; 310 } 311 } 312 #endif 313 314 /* 315 * Handler for -p option. 316 */ 317 public void 318 opt_p(type, s) 319 int type; 320 register char *s; 321 { 322 switch (type) 323 { 324 case INIT: 325 /* 326 * Unget a search command for the specified string. 327 * {{ This won't work if the "/" command is 328 * changed or invalidated by a .lesskey file. }} 329 */ 330 plusoption = TRUE; 331 ungetsc(s); 332 /* 333 * In "more" mode, the -p argument is a command, 334 * not a search string, so we don't need a slash. 335 */ 336 if (!less_is_more) 337 ungetsc("/"); 338 break; 339 } 340 } 341 342 /* 343 * Handler for -P option. 344 */ 345 public void 346 opt__P(type, s) 347 int type; 348 register char *s; 349 { 350 register char **proto; 351 PARG parg; 352 353 switch (type) 354 { 355 case INIT: 356 case TOGGLE: 357 /* 358 * Figure out which prototype string should be changed. 359 */ 360 switch (*s) 361 { 362 case 's': proto = &prproto[PR_SHORT]; s++; break; 363 case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 364 case 'M': proto = &prproto[PR_LONG]; s++; break; 365 case '=': proto = &eqproto; s++; break; 366 case 'h': proto = &hproto; s++; break; 367 case 'w': proto = &wproto; s++; break; 368 default: proto = &prproto[PR_SHORT]; break; 369 } 370 free(*proto); 371 *proto = save(s); 372 break; 373 case QUERY: 374 parg.p_string = prproto[pr_type]; 375 error("%s", &parg); 376 break; 377 } 378 } 379 380 /* 381 * Handler for the -b option. 382 */ 383 /*ARGSUSED*/ 384 public void 385 opt_b(type, s) 386 int type; 387 char *s; 388 { 389 switch (type) 390 { 391 case INIT: 392 case TOGGLE: 393 /* 394 * Set the new number of buffers. 395 */ 396 ch_setbufspace(bufspace); 397 break; 398 case QUERY: 399 break; 400 } 401 } 402 403 /* 404 * Handler for the -i option. 405 */ 406 /*ARGSUSED*/ 407 public void 408 opt_i(type, s) 409 int type; 410 char *s; 411 { 412 switch (type) 413 { 414 case TOGGLE: 415 chg_caseless(); 416 break; 417 case QUERY: 418 case INIT: 419 break; 420 } 421 } 422 423 /* 424 * Handler for the -V option. 425 */ 426 /*ARGSUSED*/ 427 public void 428 opt__V(type, s) 429 int type; 430 char *s; 431 { 432 switch (type) 433 { 434 case TOGGLE: 435 case QUERY: 436 dispversion(); 437 break; 438 case INIT: 439 /* 440 * Force output to stdout per GNU standard for --version output. 441 */ 442 any_display = 1; 443 putstr("less "); 444 putstr(version); 445 putstr("\nCopyright (C) 1984-2005 Mark Nudelman\n\n"); 446 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 447 putstr("For information about the terms of redistribution,\n"); 448 putstr("see the file named README in the less distribution.\n"); 449 putstr("Homepage: http://www.greenwoodsoftware.com/less\n"); 450 quit(QUIT_OK); 451 break; 452 } 453 } 454 455 #if MSDOS_COMPILER 456 /* 457 * Parse an MSDOS color descriptor. 458 */ 459 static void 460 colordesc(s, fg_color, bg_color) 461 char *s; 462 int *fg_color; 463 int *bg_color; 464 { 465 int fg, bg; 466 int err; 467 468 fg = getnum(&s, "D", &err); 469 if (err) 470 { 471 error("Missing fg color in -D", NULL_PARG); 472 return; 473 } 474 if (*s != '.') 475 bg = 0; 476 else 477 { 478 s++; 479 bg = getnum(&s, "D", &err); 480 if (err) 481 { 482 error("Missing fg color in -D", NULL_PARG); 483 return; 484 } 485 } 486 if (*s != '\0') 487 error("Extra characters at end of -D option", NULL_PARG); 488 *fg_color = fg; 489 *bg_color = bg; 490 } 491 492 /* 493 * Handler for the -D option. 494 */ 495 /*ARGSUSED*/ 496 public void 497 opt_D(type, s) 498 int type; 499 char *s; 500 { 501 switch (type) 502 { 503 case INIT: 504 case TOGGLE: 505 switch (*s++) 506 { 507 case 'n': 508 colordesc(s, &nm_fg_color, &nm_bg_color); 509 break; 510 case 'd': 511 colordesc(s, &bo_fg_color, &bo_bg_color); 512 break; 513 case 'u': 514 colordesc(s, &ul_fg_color, &ul_bg_color); 515 break; 516 case 'k': 517 colordesc(s, &bl_fg_color, &bl_bg_color); 518 break; 519 case 's': 520 colordesc(s, &so_fg_color, &so_bg_color); 521 break; 522 default: 523 error("-D must be followed by n, d, u, k or s", NULL_PARG); 524 break; 525 } 526 if (type == TOGGLE) 527 { 528 at_enter(AT_STANDOUT); 529 at_exit(); 530 } 531 break; 532 case QUERY: 533 break; 534 } 535 } 536 #endif 537 538 /* 539 * Handler for the -x option. 540 */ 541 public void 542 opt_x(type, s) 543 int type; 544 register char *s; 545 { 546 extern int tabstops[]; 547 extern int ntabstops; 548 extern int tabdefault; 549 char msg[60+(4*TABSTOP_MAX)]; 550 int i; 551 PARG p; 552 553 switch (type) 554 { 555 case INIT: 556 case TOGGLE: 557 /* Start at 1 because tabstops[0] is always zero. */ 558 for (i = 1; i < TABSTOP_MAX; ) 559 { 560 int n = 0; 561 s = skipsp(s); 562 while (*s >= '0' && *s <= '9') 563 n = (10 * n) + (*s++ - '0'); 564 if (n > tabstops[i-1]) 565 tabstops[i++] = n; 566 s = skipsp(s); 567 if (*s++ != ',') 568 break; 569 } 570 if (i < 2) 571 return; 572 ntabstops = i; 573 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 574 break; 575 case QUERY: 576 strcpy(msg, "Tab stops "); 577 if (ntabstops > 2) 578 { 579 for (i = 1; i < ntabstops; i++) 580 { 581 if (i > 1) 582 strcat(msg, ","); 583 sprintf(msg+strlen(msg), "%d", tabstops[i]); 584 } 585 sprintf(msg+strlen(msg), " and then "); 586 } 587 sprintf(msg+strlen(msg), "every %d spaces", 588 tabdefault); 589 p.p_string = msg; 590 error("%s", &p); 591 break; 592 } 593 } 594 595 596 /* 597 * Handler for the -" option. 598 */ 599 public void 600 opt_quote(type, s) 601 int type; 602 register char *s; 603 { 604 char buf[3]; 605 PARG parg; 606 607 switch (type) 608 { 609 case INIT: 610 case TOGGLE: 611 if (s[0] == '\0') 612 { 613 openquote = closequote = '\0'; 614 break; 615 } 616 if (s[1] != '\0' && s[2] != '\0') 617 { 618 error("-\" must be followed by 1 or 2 chars", NULL_PARG); 619 return; 620 } 621 openquote = s[0]; 622 if (s[1] == '\0') 623 closequote = openquote; 624 else 625 closequote = s[1]; 626 break; 627 case QUERY: 628 buf[0] = openquote; 629 buf[1] = closequote; 630 buf[2] = '\0'; 631 parg.p_string = buf; 632 error("quotes %s", &parg); 633 break; 634 } 635 } 636 637 /* 638 * "-?" means display a help message. 639 * If from the command line, exit immediately. 640 */ 641 /*ARGSUSED*/ 642 public void 643 opt_query(type, s) 644 int type; 645 char *s; 646 { 647 switch (type) 648 { 649 case QUERY: 650 case TOGGLE: 651 error("Use \"h\" for help", NULL_PARG); 652 break; 653 case INIT: 654 dohelp = 1; 655 } 656 } 657 658 /* 659 * Get the "screen window" size. 660 */ 661 public int 662 get_swindow() 663 { 664 if (swindow > 0) 665 return (swindow); 666 return (sc_height + swindow); 667 } 668 669