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