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