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