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