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