1 1.4 simonb /* $NetBSD: optfunc.c,v 1.4 2023/10/06 05:49:49 simonb Exp $ */ 2 1.1 tron 3 1.1 tron /* 4 1.4 simonb * Copyright (C) 1984-2023 Mark Nudelman 5 1.1 tron * 6 1.1 tron * You may distribute under the terms of either the GNU General Public 7 1.1 tron * License or the Less License, as specified in the README file. 8 1.1 tron * 9 1.3 tron * For more information, see the README file. 10 1.1 tron */ 11 1.1 tron 12 1.1 tron 13 1.1 tron /* 14 1.1 tron * Handling functions for command line options. 15 1.1 tron * 16 1.1 tron * Most options are handled by the generic code in option.c. 17 1.1 tron * But all string options, and a few non-string options, require 18 1.1 tron * special handling specific to the particular option. 19 1.1 tron * This special processing is done by the "handling functions" in this file. 20 1.1 tron * 21 1.1 tron * Each handling function is passed a "type" and, if it is a string 22 1.1 tron * option, the string which should be "assigned" to the option. 23 1.1 tron * The type may be one of: 24 1.4 simonb * INIT The option is being initialized from the command line. 25 1.4 simonb * TOGGLE The option is being changed from within the program. 26 1.4 simonb * QUERY The setting of the option is merely being queried. 27 1.1 tron */ 28 1.1 tron 29 1.1 tron #include "less.h" 30 1.1 tron #include "option.h" 31 1.1 tron 32 1.1 tron extern int nbufs; 33 1.1 tron extern int bufspace; 34 1.1 tron extern int pr_type; 35 1.1 tron extern int plusoption; 36 1.1 tron extern int swindow; 37 1.1 tron extern int sc_width; 38 1.1 tron extern int sc_height; 39 1.1 tron extern int secure; 40 1.1 tron extern int dohelp; 41 1.4 simonb extern int is_tty; 42 1.1 tron extern char openquote; 43 1.1 tron extern char closequote; 44 1.1 tron extern char *prproto[]; 45 1.1 tron extern char *eqproto; 46 1.1 tron extern char *hproto; 47 1.1 tron extern char *wproto; 48 1.4 simonb extern char *every_first_cmd; 49 1.1 tron extern IFILE curr_ifile; 50 1.1 tron extern char version[]; 51 1.1 tron extern int jump_sline; 52 1.4 simonb extern long jump_sline_fraction; 53 1.1 tron extern int shift_count; 54 1.4 simonb extern long shift_count_fraction; 55 1.4 simonb extern char rscroll_char; 56 1.4 simonb extern int rscroll_attr; 57 1.4 simonb extern int mousecap; 58 1.4 simonb extern int wheel_lines; 59 1.1 tron extern int less_is_more; 60 1.4 simonb extern int linenum_width; 61 1.4 simonb extern int status_col_width; 62 1.4 simonb extern int use_color; 63 1.4 simonb extern int want_filesize; 64 1.4 simonb extern int header_lines; 65 1.4 simonb extern int header_cols; 66 1.4 simonb extern int def_search_type; 67 1.4 simonb extern int chopline; 68 1.4 simonb extern int tabstops[]; 69 1.4 simonb extern int ntabstops; 70 1.4 simonb extern int tabdefault; 71 1.4 simonb extern char intr_char; 72 1.1 tron #if LOGFILE 73 1.1 tron extern char *namelogfile; 74 1.1 tron extern int force_logfile; 75 1.1 tron extern int logfile; 76 1.1 tron #endif 77 1.1 tron #if TAGS 78 1.1 tron public char *tagoption = NULL; 79 1.1 tron extern char *tags; 80 1.4 simonb extern char ztags[]; 81 1.1 tron #endif 82 1.4 simonb #if LESSTEST 83 1.4 simonb extern char *ttyin_name; 84 1.4 simonb #endif /*LESSTEST*/ 85 1.1 tron #if MSDOS_COMPILER 86 1.1 tron extern int nm_fg_color, nm_bg_color; 87 1.1 tron extern int bo_fg_color, bo_bg_color; 88 1.1 tron extern int ul_fg_color, ul_bg_color; 89 1.1 tron extern int so_fg_color, so_bg_color; 90 1.1 tron extern int bl_fg_color, bl_bg_color; 91 1.4 simonb extern int sgr_mode; 92 1.4 simonb #if MSDOS_COMPILER==WIN32C 93 1.4 simonb #ifndef COMMON_LVB_UNDERSCORE 94 1.4 simonb #define COMMON_LVB_UNDERSCORE 0x8000 95 1.4 simonb #endif 96 1.4 simonb #endif 97 1.1 tron #endif 98 1.1 tron 99 1.1 tron 100 1.1 tron #if LOGFILE 101 1.1 tron /* 102 1.1 tron * Handler for -o option. 103 1.1 tron */ 104 1.4 simonb public void opt_o(int type, char *s) 105 1.1 tron { 106 1.1 tron PARG parg; 107 1.4 simonb char *filename; 108 1.1 tron 109 1.1 tron if (secure) 110 1.1 tron { 111 1.1 tron error("log file support is not available", NULL_PARG); 112 1.1 tron return; 113 1.1 tron } 114 1.1 tron switch (type) 115 1.1 tron { 116 1.1 tron case INIT: 117 1.4 simonb namelogfile = save(s); 118 1.1 tron break; 119 1.1 tron case TOGGLE: 120 1.1 tron if (ch_getflags() & CH_CANSEEK) 121 1.1 tron { 122 1.1 tron error("Input is not a pipe", NULL_PARG); 123 1.1 tron return; 124 1.1 tron } 125 1.1 tron if (logfile >= 0) 126 1.1 tron { 127 1.1 tron error("Log file is already in use", NULL_PARG); 128 1.1 tron return; 129 1.1 tron } 130 1.1 tron s = skipsp(s); 131 1.4 simonb if (namelogfile != NULL) 132 1.4 simonb free(namelogfile); 133 1.4 simonb filename = lglob(s); 134 1.4 simonb namelogfile = shell_unquote(filename); 135 1.4 simonb free(filename); 136 1.1 tron use_logfile(namelogfile); 137 1.1 tron sync_logfile(); 138 1.1 tron break; 139 1.1 tron case QUERY: 140 1.1 tron if (logfile < 0) 141 1.1 tron error("No log file", NULL_PARG); 142 1.1 tron else 143 1.1 tron { 144 1.1 tron parg.p_string = namelogfile; 145 1.1 tron error("Log file \"%s\"", &parg); 146 1.1 tron } 147 1.1 tron break; 148 1.1 tron } 149 1.1 tron } 150 1.1 tron 151 1.1 tron /* 152 1.1 tron * Handler for -O option. 153 1.1 tron */ 154 1.4 simonb public void opt__O(int type, char *s) 155 1.1 tron { 156 1.1 tron force_logfile = TRUE; 157 1.1 tron opt_o(type, s); 158 1.1 tron } 159 1.1 tron #endif 160 1.1 tron 161 1.1 tron /* 162 1.1 tron * Handlers for -j option. 163 1.1 tron */ 164 1.4 simonb public void opt_j(int type, char *s) 165 1.1 tron { 166 1.1 tron PARG parg; 167 1.1 tron int len; 168 1.1 tron int err; 169 1.1 tron 170 1.1 tron switch (type) 171 1.1 tron { 172 1.1 tron case INIT: 173 1.1 tron case TOGGLE: 174 1.1 tron if (*s == '.') 175 1.1 tron { 176 1.1 tron s++; 177 1.1 tron jump_sline_fraction = getfraction(&s, "j", &err); 178 1.1 tron if (err) 179 1.1 tron error("Invalid line fraction", NULL_PARG); 180 1.1 tron else 181 1.1 tron calc_jump_sline(); 182 1.1 tron } else 183 1.1 tron { 184 1.1 tron int sline = getnum(&s, "j", &err); 185 1.1 tron if (err) 186 1.1 tron error("Invalid line number", NULL_PARG); 187 1.1 tron else 188 1.1 tron { 189 1.1 tron jump_sline = sline; 190 1.1 tron jump_sline_fraction = -1; 191 1.1 tron } 192 1.1 tron } 193 1.1 tron break; 194 1.1 tron case QUERY: 195 1.1 tron if (jump_sline_fraction < 0) 196 1.1 tron { 197 1.1 tron parg.p_int = jump_sline; 198 1.1 tron error("Position target at screen line %d", &parg); 199 1.1 tron } else 200 1.1 tron { 201 1.4 simonb char buf[INT_STRLEN_BOUND(long)+2]; 202 1.4 simonb SNPRINTF1(buf, sizeof(buf), ".%06ld", jump_sline_fraction); 203 1.4 simonb len = (int) strlen(buf); 204 1.1 tron while (len > 2 && buf[len-1] == '0') 205 1.1 tron len--; 206 1.1 tron buf[len] = '\0'; 207 1.1 tron parg.p_string = buf; 208 1.1 tron error("Position target at screen position %s", &parg); 209 1.1 tron } 210 1.1 tron break; 211 1.1 tron } 212 1.1 tron } 213 1.1 tron 214 1.4 simonb public void calc_jump_sline(void) 215 1.1 tron { 216 1.1 tron if (jump_sline_fraction < 0) 217 1.1 tron return; 218 1.4 simonb jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM); 219 1.1 tron } 220 1.1 tron 221 1.1 tron /* 222 1.1 tron * Handlers for -# option. 223 1.1 tron */ 224 1.4 simonb public void opt_shift(int type, char *s) 225 1.1 tron { 226 1.1 tron PARG parg; 227 1.1 tron int len; 228 1.1 tron int err; 229 1.1 tron 230 1.1 tron switch (type) 231 1.1 tron { 232 1.1 tron case INIT: 233 1.1 tron case TOGGLE: 234 1.1 tron if (*s == '.') 235 1.1 tron { 236 1.1 tron s++; 237 1.1 tron shift_count_fraction = getfraction(&s, "#", &err); 238 1.1 tron if (err) 239 1.1 tron error("Invalid column fraction", NULL_PARG); 240 1.1 tron else 241 1.1 tron calc_shift_count(); 242 1.1 tron } else 243 1.1 tron { 244 1.1 tron int hs = getnum(&s, "#", &err); 245 1.1 tron if (err) 246 1.1 tron error("Invalid column number", NULL_PARG); 247 1.1 tron else 248 1.1 tron { 249 1.1 tron shift_count = hs; 250 1.1 tron shift_count_fraction = -1; 251 1.1 tron } 252 1.1 tron } 253 1.1 tron break; 254 1.1 tron case QUERY: 255 1.1 tron if (shift_count_fraction < 0) 256 1.1 tron { 257 1.1 tron parg.p_int = shift_count; 258 1.1 tron error("Horizontal shift %d columns", &parg); 259 1.1 tron } else 260 1.1 tron { 261 1.4 simonb char buf[INT_STRLEN_BOUND(long)+2]; 262 1.4 simonb SNPRINTF1(buf, sizeof(buf), ".%06ld", shift_count_fraction); 263 1.4 simonb len = (int) strlen(buf); 264 1.1 tron while (len > 2 && buf[len-1] == '0') 265 1.1 tron len--; 266 1.1 tron buf[len] = '\0'; 267 1.1 tron parg.p_string = buf; 268 1.1 tron error("Horizontal shift %s of screen width", &parg); 269 1.1 tron } 270 1.1 tron break; 271 1.1 tron } 272 1.1 tron } 273 1.4 simonb 274 1.4 simonb public void calc_shift_count(void) 275 1.1 tron { 276 1.1 tron if (shift_count_fraction < 0) 277 1.1 tron return; 278 1.4 simonb shift_count = (int) muldiv(sc_width, shift_count_fraction, NUM_FRAC_DENOM); 279 1.1 tron } 280 1.1 tron 281 1.1 tron #if USERFILE 282 1.4 simonb public void opt_k(int type, char *s) 283 1.1 tron { 284 1.1 tron PARG parg; 285 1.1 tron 286 1.1 tron switch (type) 287 1.1 tron { 288 1.1 tron case INIT: 289 1.1 tron if (lesskey(s, 0)) 290 1.1 tron { 291 1.1 tron parg.p_string = s; 292 1.1 tron error("Cannot use lesskey file \"%s\"", &parg); 293 1.1 tron } 294 1.1 tron break; 295 1.1 tron } 296 1.1 tron } 297 1.4 simonb 298 1.4 simonb #if HAVE_LESSKEYSRC 299 1.4 simonb public void opt_ks(int type, char *s) 300 1.4 simonb { 301 1.4 simonb PARG parg; 302 1.4 simonb 303 1.4 simonb switch (type) 304 1.4 simonb { 305 1.4 simonb case INIT: 306 1.4 simonb if (lesskey_src(s, 0)) 307 1.4 simonb { 308 1.4 simonb parg.p_string = s; 309 1.4 simonb error("Cannot use lesskey source file \"%s\"", &parg); 310 1.4 simonb } 311 1.4 simonb break; 312 1.4 simonb } 313 1.4 simonb } 314 1.4 simonb #endif /* HAVE_LESSKEYSRC */ 315 1.4 simonb #endif /* USERFILE */ 316 1.1 tron 317 1.1 tron #if TAGS 318 1.1 tron /* 319 1.1 tron * Handler for -t option. 320 1.1 tron */ 321 1.4 simonb public void opt_t(int type, char *s) 322 1.1 tron { 323 1.1 tron IFILE save_ifile; 324 1.1 tron POSITION pos; 325 1.1 tron 326 1.1 tron switch (type) 327 1.1 tron { 328 1.1 tron case INIT: 329 1.4 simonb tagoption = save(s); 330 1.1 tron /* Do the rest in main() */ 331 1.1 tron break; 332 1.1 tron case TOGGLE: 333 1.1 tron if (secure) 334 1.1 tron { 335 1.1 tron error("tags support is not available", NULL_PARG); 336 1.1 tron break; 337 1.1 tron } 338 1.1 tron findtag(skipsp(s)); 339 1.1 tron save_ifile = save_curr_ifile(); 340 1.1 tron /* 341 1.1 tron * Try to open the file containing the tag 342 1.1 tron * and search for the tag in that file. 343 1.1 tron */ 344 1.1 tron if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 345 1.1 tron { 346 1.1 tron /* Failed: reopen the old file. */ 347 1.1 tron reedit_ifile(save_ifile); 348 1.1 tron break; 349 1.1 tron } 350 1.1 tron unsave_ifile(save_ifile); 351 1.1 tron jump_loc(pos, jump_sline); 352 1.1 tron break; 353 1.1 tron } 354 1.1 tron } 355 1.1 tron 356 1.1 tron /* 357 1.1 tron * Handler for -T option. 358 1.1 tron */ 359 1.4 simonb public void opt__T(int type, char *s) 360 1.1 tron { 361 1.1 tron PARG parg; 362 1.4 simonb char *filename; 363 1.1 tron 364 1.1 tron switch (type) 365 1.1 tron { 366 1.1 tron case INIT: 367 1.4 simonb tags = save(s); 368 1.1 tron break; 369 1.1 tron case TOGGLE: 370 1.1 tron s = skipsp(s); 371 1.4 simonb if (tags != NULL && tags != ztags) 372 1.4 simonb free(tags); 373 1.4 simonb filename = lglob(s); 374 1.4 simonb tags = shell_unquote(filename); 375 1.4 simonb free(filename); 376 1.1 tron break; 377 1.1 tron case QUERY: 378 1.1 tron parg.p_string = tags; 379 1.1 tron error("Tags file \"%s\"", &parg); 380 1.1 tron break; 381 1.1 tron } 382 1.1 tron } 383 1.1 tron #endif 384 1.1 tron 385 1.1 tron /* 386 1.1 tron * Handler for -p option. 387 1.1 tron */ 388 1.4 simonb public void opt_p(int type, char *s) 389 1.1 tron { 390 1.1 tron switch (type) 391 1.1 tron { 392 1.1 tron case INIT: 393 1.1 tron /* 394 1.4 simonb * Unget a command for the specified string. 395 1.1 tron */ 396 1.4 simonb if (less_is_more) 397 1.4 simonb { 398 1.4 simonb /* 399 1.4 simonb * In "more" mode, the -p argument is a command, 400 1.4 simonb * not a search string, so we don't need a slash. 401 1.4 simonb */ 402 1.4 simonb every_first_cmd = save(s); 403 1.4 simonb } else 404 1.4 simonb { 405 1.4 simonb plusoption = TRUE; 406 1.4 simonb /* 407 1.4 simonb * {{ This won't work if the "/" command is 408 1.4 simonb * changed or invalidated by a .lesskey file. }} 409 1.4 simonb */ 410 1.1 tron ungetsc("/"); 411 1.4 simonb ungetsc(s); 412 1.4 simonb ungetcc_back(CHAR_END_COMMAND); 413 1.4 simonb } 414 1.1 tron break; 415 1.1 tron } 416 1.1 tron } 417 1.1 tron 418 1.1 tron /* 419 1.1 tron * Handler for -P option. 420 1.1 tron */ 421 1.4 simonb public void opt__P(int type, char *s) 422 1.1 tron { 423 1.4 simonb char **proto; 424 1.1 tron PARG parg; 425 1.1 tron 426 1.1 tron switch (type) 427 1.1 tron { 428 1.1 tron case INIT: 429 1.1 tron case TOGGLE: 430 1.1 tron /* 431 1.1 tron * Figure out which prototype string should be changed. 432 1.1 tron */ 433 1.1 tron switch (*s) 434 1.1 tron { 435 1.4 simonb case 's': proto = &prproto[PR_SHORT]; s++; break; 436 1.4 simonb case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 437 1.4 simonb case 'M': proto = &prproto[PR_LONG]; s++; break; 438 1.4 simonb case '=': proto = &eqproto; s++; break; 439 1.4 simonb case 'h': proto = &hproto; s++; break; 440 1.4 simonb case 'w': proto = &wproto; s++; break; 441 1.4 simonb default: proto = &prproto[PR_SHORT]; break; 442 1.1 tron } 443 1.1 tron free(*proto); 444 1.1 tron *proto = save(s); 445 1.1 tron break; 446 1.1 tron case QUERY: 447 1.1 tron parg.p_string = prproto[pr_type]; 448 1.1 tron error("%s", &parg); 449 1.1 tron break; 450 1.1 tron } 451 1.1 tron } 452 1.1 tron 453 1.1 tron /* 454 1.1 tron * Handler for the -b option. 455 1.1 tron */ 456 1.1 tron /*ARGSUSED*/ 457 1.4 simonb public void opt_b(int type, char *s) 458 1.1 tron { 459 1.1 tron switch (type) 460 1.1 tron { 461 1.1 tron case INIT: 462 1.1 tron case TOGGLE: 463 1.1 tron /* 464 1.1 tron * Set the new number of buffers. 465 1.1 tron */ 466 1.1 tron ch_setbufspace(bufspace); 467 1.1 tron break; 468 1.1 tron case QUERY: 469 1.1 tron break; 470 1.1 tron } 471 1.1 tron } 472 1.1 tron 473 1.1 tron /* 474 1.1 tron * Handler for the -i option. 475 1.1 tron */ 476 1.1 tron /*ARGSUSED*/ 477 1.4 simonb public void opt_i(int type, char *s) 478 1.1 tron { 479 1.1 tron switch (type) 480 1.1 tron { 481 1.1 tron case TOGGLE: 482 1.1 tron chg_caseless(); 483 1.1 tron break; 484 1.1 tron case QUERY: 485 1.1 tron case INIT: 486 1.1 tron break; 487 1.1 tron } 488 1.1 tron } 489 1.1 tron 490 1.1 tron /* 491 1.1 tron * Handler for the -V option. 492 1.1 tron */ 493 1.1 tron /*ARGSUSED*/ 494 1.4 simonb public void opt__V(int type, char *s) 495 1.1 tron { 496 1.1 tron switch (type) 497 1.1 tron { 498 1.1 tron case TOGGLE: 499 1.1 tron case QUERY: 500 1.1 tron dispversion(); 501 1.1 tron break; 502 1.1 tron case INIT: 503 1.4 simonb set_output(1); /* Force output to stdout per GNU standard for --version output. */ 504 1.1 tron putstr("less "); 505 1.1 tron putstr(version); 506 1.3 tron putstr(" ("); 507 1.4 simonb putstr(pattern_lib_name()); 508 1.4 simonb putstr(" regular expressions)\n"); 509 1.4 simonb { 510 1.4 simonb char constant *copyright = 511 1.4 simonb "Copyright (C) 1984-2023 Mark Nudelman\n\n"; 512 1.4 simonb putstr(copyright); 513 1.4 simonb } 514 1.4 simonb if (version[strlen(version)-1] == 'x') 515 1.4 simonb { 516 1.4 simonb putstr("** This is an EXPERIMENTAL build of the 'less' software,\n"); 517 1.4 simonb putstr("** and may not function correctly.\n"); 518 1.4 simonb putstr("** Obtain release builds from the web page below.\n\n"); 519 1.4 simonb } 520 1.4 simonb #if LESSTEST 521 1.4 simonb putstr("This build supports LESSTEST.\n"); 522 1.4 simonb #endif /*LESSTEST*/ 523 1.1 tron putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 524 1.1 tron putstr("For information about the terms of redistribution,\n"); 525 1.1 tron putstr("see the file named README in the less distribution.\n"); 526 1.4 simonb putstr("Home page: https://greenwoodsoftware.com/less\n"); 527 1.1 tron quit(QUIT_OK); 528 1.1 tron break; 529 1.1 tron } 530 1.1 tron } 531 1.1 tron 532 1.1 tron #if MSDOS_COMPILER 533 1.1 tron /* 534 1.1 tron * Parse an MSDOS color descriptor. 535 1.1 tron */ 536 1.4 simonb static void colordesc(char *s, int *fg_color, int *bg_color) 537 1.1 tron { 538 1.1 tron int fg, bg; 539 1.4 simonb #if MSDOS_COMPILER==WIN32C 540 1.4 simonb int ul = 0; 541 1.4 simonb 542 1.4 simonb if (*s == 'u') 543 1.1 tron { 544 1.4 simonb ul = COMMON_LVB_UNDERSCORE; 545 1.1 tron s++; 546 1.4 simonb if (*s == '\0') 547 1.1 tron { 548 1.4 simonb *fg_color = nm_fg_color | ul; 549 1.4 simonb *bg_color = nm_bg_color; 550 1.1 tron return; 551 1.1 tron } 552 1.1 tron } 553 1.4 simonb #endif 554 1.4 simonb if (parse_color(s, &fg, &bg) == CT_NULL) 555 1.4 simonb { 556 1.4 simonb PARG p; 557 1.4 simonb p.p_string = s; 558 1.4 simonb error("Invalid color string \"%s\"", &p); 559 1.4 simonb } else 560 1.4 simonb { 561 1.4 simonb if (fg == CV_NOCHANGE) 562 1.4 simonb fg = nm_fg_color; 563 1.4 simonb if (bg == CV_NOCHANGE) 564 1.4 simonb bg = nm_bg_color; 565 1.4 simonb #if MSDOS_COMPILER==WIN32C 566 1.4 simonb fg |= ul; 567 1.4 simonb #endif 568 1.4 simonb *fg_color = fg; 569 1.4 simonb *bg_color = bg; 570 1.4 simonb } 571 1.4 simonb } 572 1.4 simonb #endif 573 1.4 simonb 574 1.4 simonb static int color_from_namechar(char namechar) 575 1.4 simonb { 576 1.4 simonb switch (namechar) 577 1.4 simonb { 578 1.4 simonb case 'B': return AT_COLOR_BIN; 579 1.4 simonb case 'C': return AT_COLOR_CTRL; 580 1.4 simonb case 'E': return AT_COLOR_ERROR; 581 1.4 simonb case 'H': return AT_COLOR_HEADER; 582 1.4 simonb case 'M': return AT_COLOR_MARK; 583 1.4 simonb case 'N': return AT_COLOR_LINENUM; 584 1.4 simonb case 'P': return AT_COLOR_PROMPT; 585 1.4 simonb case 'R': return AT_COLOR_RSCROLL; 586 1.4 simonb case 'S': return AT_COLOR_SEARCH; 587 1.4 simonb case 'W': case 'A': return AT_COLOR_ATTN; 588 1.4 simonb case 'n': return AT_NORMAL; 589 1.4 simonb case 's': return AT_STANDOUT; 590 1.4 simonb case 'd': return AT_BOLD; 591 1.4 simonb case 'u': return AT_UNDERLINE; 592 1.4 simonb case 'k': return AT_BLINK; 593 1.4 simonb default: 594 1.4 simonb if (namechar >= '1' && namechar <= '0'+NUM_SEARCH_COLORS) 595 1.4 simonb return AT_COLOR_SUBSEARCH(namechar-'0'); 596 1.4 simonb return -1; 597 1.4 simonb } 598 1.1 tron } 599 1.1 tron 600 1.1 tron /* 601 1.1 tron * Handler for the -D option. 602 1.1 tron */ 603 1.1 tron /*ARGSUSED*/ 604 1.4 simonb public void opt_D(int type, char *s) 605 1.1 tron { 606 1.4 simonb PARG p; 607 1.4 simonb int attr; 608 1.4 simonb 609 1.1 tron switch (type) 610 1.1 tron { 611 1.1 tron case INIT: 612 1.1 tron case TOGGLE: 613 1.4 simonb #if MSDOS_COMPILER 614 1.4 simonb if (*s == 'a') 615 1.1 tron { 616 1.4 simonb sgr_mode = !sgr_mode; 617 1.1 tron break; 618 1.1 tron } 619 1.4 simonb #endif 620 1.4 simonb attr = color_from_namechar(s[0]); 621 1.4 simonb if (attr < 0) 622 1.4 simonb { 623 1.4 simonb p.p_char = s[0]; 624 1.4 simonb error("Invalid color specifier '%c'", &p); 625 1.4 simonb return; 626 1.4 simonb } 627 1.4 simonb if (!use_color && (attr & AT_COLOR)) 628 1.4 simonb { 629 1.4 simonb error("Set --use-color before changing colors", NULL_PARG); 630 1.4 simonb return; 631 1.4 simonb } 632 1.4 simonb s++; 633 1.4 simonb #if MSDOS_COMPILER 634 1.4 simonb if (!(attr & AT_COLOR)) 635 1.4 simonb { 636 1.4 simonb switch (attr) 637 1.4 simonb { 638 1.4 simonb case AT_NORMAL: 639 1.4 simonb colordesc(s, &nm_fg_color, &nm_bg_color); 640 1.4 simonb break; 641 1.4 simonb case AT_BOLD: 642 1.4 simonb colordesc(s, &bo_fg_color, &bo_bg_color); 643 1.4 simonb break; 644 1.4 simonb case AT_UNDERLINE: 645 1.4 simonb colordesc(s, &ul_fg_color, &ul_bg_color); 646 1.4 simonb break; 647 1.4 simonb case AT_BLINK: 648 1.4 simonb colordesc(s, &bl_fg_color, &bl_bg_color); 649 1.4 simonb break; 650 1.4 simonb case AT_STANDOUT: 651 1.4 simonb colordesc(s, &so_fg_color, &so_bg_color); 652 1.4 simonb break; 653 1.4 simonb } 654 1.4 simonb if (type == TOGGLE) 655 1.4 simonb { 656 1.4 simonb at_enter(AT_STANDOUT); 657 1.4 simonb at_exit(); 658 1.4 simonb } 659 1.4 simonb } else 660 1.4 simonb #endif 661 1.4 simonb if (set_color_map(attr, s) < 0) 662 1.1 tron { 663 1.4 simonb p.p_string = s; 664 1.4 simonb error("Invalid color string \"%s\"", &p); 665 1.4 simonb return; 666 1.1 tron } 667 1.1 tron break; 668 1.4 simonb #if MSDOS_COMPILER 669 1.1 tron case QUERY: 670 1.4 simonb p.p_string = (sgr_mode) ? "on" : "off"; 671 1.4 simonb error("SGR mode is %s", &p); 672 1.1 tron break; 673 1.4 simonb #endif 674 1.1 tron } 675 1.1 tron } 676 1.4 simonb 677 1.4 simonb /* 678 1.4 simonb */ 679 1.4 simonb public void set_tabs(char *s, int len) 680 1.4 simonb { 681 1.4 simonb int i; 682 1.4 simonb char *es = s + len; 683 1.4 simonb /* Start at 1 because tabstops[0] is always zero. */ 684 1.4 simonb for (i = 1; i < TABSTOP_MAX; ) 685 1.4 simonb { 686 1.4 simonb int n = 0; 687 1.4 simonb int v = FALSE; 688 1.4 simonb while (s < es && *s == ' ') 689 1.4 simonb s++; 690 1.4 simonb for (; s < es && *s >= '0' && *s <= '9'; s++) 691 1.4 simonb { 692 1.4 simonb v |= ckd_mul(&n, n, 10); 693 1.4 simonb v |= ckd_add(&n, n, *s - '0'); 694 1.4 simonb } 695 1.4 simonb if (!v && n > tabstops[i-1]) 696 1.4 simonb tabstops[i++] = n; 697 1.4 simonb while (s < es && *s == ' ') 698 1.4 simonb s++; 699 1.4 simonb if (s == es || *s++ != ',') 700 1.4 simonb break; 701 1.4 simonb } 702 1.4 simonb if (i < 2) 703 1.4 simonb return; 704 1.4 simonb ntabstops = i; 705 1.4 simonb tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 706 1.4 simonb } 707 1.1 tron 708 1.1 tron /* 709 1.1 tron * Handler for the -x option. 710 1.1 tron */ 711 1.4 simonb public void opt_x(int type, char *s) 712 1.4 simonb { 713 1.4 simonb char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)]; 714 1.1 tron int i; 715 1.1 tron PARG p; 716 1.1 tron 717 1.1 tron switch (type) 718 1.1 tron { 719 1.1 tron case INIT: 720 1.1 tron case TOGGLE: 721 1.4 simonb set_tabs(s, strlen(s)); 722 1.1 tron break; 723 1.1 tron case QUERY: 724 1.1 tron strcpy(msg, "Tab stops "); 725 1.1 tron if (ntabstops > 2) 726 1.1 tron { 727 1.1 tron for (i = 1; i < ntabstops; i++) 728 1.1 tron { 729 1.1 tron if (i > 1) 730 1.1 tron strcat(msg, ","); 731 1.1 tron sprintf(msg+strlen(msg), "%d", tabstops[i]); 732 1.1 tron } 733 1.1 tron sprintf(msg+strlen(msg), " and then "); 734 1.1 tron } 735 1.1 tron sprintf(msg+strlen(msg), "every %d spaces", 736 1.1 tron tabdefault); 737 1.1 tron p.p_string = msg; 738 1.1 tron error("%s", &p); 739 1.1 tron break; 740 1.1 tron } 741 1.1 tron } 742 1.1 tron 743 1.1 tron 744 1.1 tron /* 745 1.1 tron * Handler for the -" option. 746 1.1 tron */ 747 1.4 simonb public void opt_quote(int type, char *s) 748 1.1 tron { 749 1.1 tron char buf[3]; 750 1.1 tron PARG parg; 751 1.1 tron 752 1.1 tron switch (type) 753 1.1 tron { 754 1.1 tron case INIT: 755 1.1 tron case TOGGLE: 756 1.1 tron if (s[0] == '\0') 757 1.1 tron { 758 1.1 tron openquote = closequote = '\0'; 759 1.1 tron break; 760 1.1 tron } 761 1.1 tron if (s[1] != '\0' && s[2] != '\0') 762 1.1 tron { 763 1.1 tron error("-\" must be followed by 1 or 2 chars", NULL_PARG); 764 1.1 tron return; 765 1.1 tron } 766 1.1 tron openquote = s[0]; 767 1.1 tron if (s[1] == '\0') 768 1.1 tron closequote = openquote; 769 1.1 tron else 770 1.1 tron closequote = s[1]; 771 1.1 tron break; 772 1.1 tron case QUERY: 773 1.1 tron buf[0] = openquote; 774 1.1 tron buf[1] = closequote; 775 1.1 tron buf[2] = '\0'; 776 1.1 tron parg.p_string = buf; 777 1.1 tron error("quotes %s", &parg); 778 1.1 tron break; 779 1.1 tron } 780 1.1 tron } 781 1.1 tron 782 1.1 tron /* 783 1.4 simonb * Handler for the --rscroll option. 784 1.4 simonb */ 785 1.4 simonb /*ARGSUSED*/ 786 1.4 simonb public void opt_rscroll(int type, char *s) 787 1.4 simonb { 788 1.4 simonb PARG p; 789 1.4 simonb 790 1.4 simonb switch (type) 791 1.4 simonb { 792 1.4 simonb case INIT: 793 1.4 simonb case TOGGLE: { 794 1.4 simonb char *fmt; 795 1.4 simonb int attr = AT_STANDOUT; 796 1.4 simonb setfmt(s, &fmt, &attr, "*s>", FALSE); 797 1.4 simonb if (strcmp(fmt, "-") == 0) 798 1.4 simonb { 799 1.4 simonb rscroll_char = 0; 800 1.4 simonb } else 801 1.4 simonb { 802 1.4 simonb rscroll_char = *fmt ? *fmt : '>'; 803 1.4 simonb rscroll_attr = attr|AT_COLOR_RSCROLL; 804 1.4 simonb } 805 1.4 simonb break; } 806 1.4 simonb case QUERY: { 807 1.4 simonb p.p_string = rscroll_char ? prchar(rscroll_char) : "-"; 808 1.4 simonb error("rscroll character is %s", &p); 809 1.4 simonb break; } 810 1.4 simonb } 811 1.4 simonb } 812 1.4 simonb 813 1.4 simonb /* 814 1.1 tron * "-?" means display a help message. 815 1.1 tron * If from the command line, exit immediately. 816 1.1 tron */ 817 1.1 tron /*ARGSUSED*/ 818 1.4 simonb public void opt_query(int type, char *s) 819 1.1 tron { 820 1.1 tron switch (type) 821 1.1 tron { 822 1.1 tron case QUERY: 823 1.1 tron case TOGGLE: 824 1.1 tron error("Use \"h\" for help", NULL_PARG); 825 1.1 tron break; 826 1.1 tron case INIT: 827 1.1 tron dohelp = 1; 828 1.1 tron } 829 1.1 tron } 830 1.1 tron 831 1.1 tron /* 832 1.4 simonb * Handler for the --mouse option. 833 1.4 simonb */ 834 1.4 simonb /*ARGSUSED*/ 835 1.4 simonb public void opt_mousecap(int type, char *s) 836 1.4 simonb { 837 1.4 simonb switch (type) 838 1.4 simonb { 839 1.4 simonb case TOGGLE: 840 1.4 simonb if (mousecap == OPT_OFF) 841 1.4 simonb deinit_mouse(); 842 1.4 simonb else 843 1.4 simonb init_mouse(); 844 1.4 simonb break; 845 1.4 simonb case INIT: 846 1.4 simonb case QUERY: 847 1.4 simonb break; 848 1.4 simonb } 849 1.4 simonb } 850 1.4 simonb 851 1.4 simonb /* 852 1.4 simonb * Handler for the --wheel-lines option. 853 1.4 simonb */ 854 1.4 simonb /*ARGSUSED*/ 855 1.4 simonb public void opt_wheel_lines(int type, char *s) 856 1.4 simonb { 857 1.4 simonb switch (type) 858 1.4 simonb { 859 1.4 simonb case INIT: 860 1.4 simonb case TOGGLE: 861 1.4 simonb if (wheel_lines <= 0) 862 1.4 simonb wheel_lines = default_wheel_lines(); 863 1.4 simonb break; 864 1.4 simonb case QUERY: 865 1.4 simonb break; 866 1.4 simonb } 867 1.4 simonb } 868 1.4 simonb 869 1.4 simonb /* 870 1.4 simonb * Handler for the --line-number-width option. 871 1.4 simonb */ 872 1.4 simonb /*ARGSUSED*/ 873 1.4 simonb public void opt_linenum_width(int type, char *s) 874 1.4 simonb { 875 1.4 simonb PARG parg; 876 1.4 simonb 877 1.4 simonb switch (type) 878 1.4 simonb { 879 1.4 simonb case INIT: 880 1.4 simonb case TOGGLE: 881 1.4 simonb if (linenum_width > MAX_LINENUM_WIDTH) 882 1.4 simonb { 883 1.4 simonb parg.p_int = MAX_LINENUM_WIDTH; 884 1.4 simonb error("Line number width must not be larger than %d", &parg); 885 1.4 simonb linenum_width = MIN_LINENUM_WIDTH; 886 1.4 simonb } 887 1.4 simonb break; 888 1.4 simonb case QUERY: 889 1.4 simonb break; 890 1.4 simonb } 891 1.4 simonb } 892 1.4 simonb 893 1.4 simonb /* 894 1.4 simonb * Handler for the --status-column-width option. 895 1.4 simonb */ 896 1.4 simonb /*ARGSUSED*/ 897 1.4 simonb public void opt_status_col_width(int type, char *s) 898 1.4 simonb { 899 1.4 simonb PARG parg; 900 1.4 simonb 901 1.4 simonb switch (type) 902 1.4 simonb { 903 1.4 simonb case INIT: 904 1.4 simonb case TOGGLE: 905 1.4 simonb if (status_col_width > MAX_STATUSCOL_WIDTH) 906 1.4 simonb { 907 1.4 simonb parg.p_int = MAX_STATUSCOL_WIDTH; 908 1.4 simonb error("Status column width must not be larger than %d", &parg); 909 1.4 simonb status_col_width = 2; 910 1.4 simonb } 911 1.4 simonb break; 912 1.4 simonb case QUERY: 913 1.4 simonb break; 914 1.4 simonb } 915 1.4 simonb } 916 1.4 simonb 917 1.4 simonb /* 918 1.4 simonb * Handler for the --file-size option. 919 1.4 simonb */ 920 1.4 simonb /*ARGSUSED*/ 921 1.4 simonb public void opt_filesize(int type, char *s) 922 1.4 simonb { 923 1.4 simonb switch (type) 924 1.4 simonb { 925 1.4 simonb case INIT: 926 1.4 simonb case TOGGLE: 927 1.4 simonb if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION) 928 1.4 simonb scan_eof(); 929 1.4 simonb break; 930 1.4 simonb case QUERY: 931 1.4 simonb break; 932 1.4 simonb } 933 1.4 simonb } 934 1.4 simonb 935 1.4 simonb /* 936 1.4 simonb * Handler for the --intr option. 937 1.4 simonb */ 938 1.4 simonb /*ARGSUSED*/ 939 1.4 simonb public void opt_intr(int type, char *s) 940 1.4 simonb { 941 1.4 simonb PARG p; 942 1.4 simonb 943 1.4 simonb switch (type) 944 1.4 simonb { 945 1.4 simonb case INIT: 946 1.4 simonb case TOGGLE: 947 1.4 simonb intr_char = *s; 948 1.4 simonb if (intr_char == '^' && s[1] != '\0') 949 1.4 simonb intr_char = CONTROL(s[1]); 950 1.4 simonb break; 951 1.4 simonb case QUERY: { 952 1.4 simonb p.p_string = prchar(intr_char); 953 1.4 simonb error("interrupt character is %s", &p); 954 1.4 simonb break; } 955 1.4 simonb } 956 1.4 simonb } 957 1.4 simonb 958 1.4 simonb /* 959 1.4 simonb * Handler for the --header option. 960 1.4 simonb */ 961 1.4 simonb /*ARGSUSED*/ 962 1.4 simonb public void opt_header(int type, char *s) 963 1.4 simonb { 964 1.4 simonb int err; 965 1.4 simonb int n; 966 1.4 simonb 967 1.4 simonb switch (type) 968 1.4 simonb { 969 1.4 simonb case INIT: 970 1.4 simonb case TOGGLE: 971 1.4 simonb header_lines = 0; 972 1.4 simonb header_cols = 0; 973 1.4 simonb if (*s != ',') 974 1.4 simonb { 975 1.4 simonb n = getnum(&s, "header", &err); 976 1.4 simonb if (err) 977 1.4 simonb { 978 1.4 simonb error("invalid number of lines", NULL_PARG); 979 1.4 simonb return; 980 1.4 simonb } 981 1.4 simonb header_lines = n; 982 1.4 simonb } 983 1.4 simonb if (*s == ',') 984 1.4 simonb { 985 1.4 simonb ++s; 986 1.4 simonb n = getnum(&s, "header", &err); 987 1.4 simonb if (err) 988 1.4 simonb error("invalid number of columns", NULL_PARG); 989 1.4 simonb else 990 1.4 simonb header_cols = n; 991 1.4 simonb } 992 1.4 simonb break; 993 1.4 simonb case QUERY: 994 1.4 simonb { 995 1.4 simonb char buf[2*INT_STRLEN_BOUND(int)+2]; 996 1.4 simonb PARG parg; 997 1.4 simonb SNPRINTF2(buf, sizeof(buf), "%d,%d", header_lines, header_cols); 998 1.4 simonb parg.p_string = buf; 999 1.4 simonb error("header (lines,columns) is %s", &parg); 1000 1.4 simonb } 1001 1.4 simonb break; 1002 1.4 simonb } 1003 1.4 simonb } 1004 1.4 simonb 1005 1.4 simonb /* 1006 1.4 simonb * Handler for the --search-options option. 1007 1.4 simonb */ 1008 1.4 simonb /*ARGSUSED*/ 1009 1.4 simonb public void opt_search_type(int type, char *s) 1010 1.4 simonb { 1011 1.4 simonb int st; 1012 1.4 simonb PARG parg; 1013 1.4 simonb char buf[16]; 1014 1.4 simonb char *bp; 1015 1.4 simonb int i; 1016 1.4 simonb 1017 1.4 simonb switch (type) 1018 1.4 simonb { 1019 1.4 simonb case INIT: 1020 1.4 simonb case TOGGLE: 1021 1.4 simonb st = 0; 1022 1.4 simonb for (; *s != '\0'; s++) 1023 1.4 simonb { 1024 1.4 simonb switch (*s) 1025 1.4 simonb { 1026 1.4 simonb case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF; break; 1027 1.4 simonb case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break; 1028 1.4 simonb case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE; break; 1029 1.4 simonb case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH; break; 1030 1.4 simonb case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX; break; 1031 1.4 simonb case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP; break; 1032 1.4 simonb case '-': st = 0; break; 1033 1.4 simonb case '^': break; 1034 1.4 simonb default: 1035 1.4 simonb if (*s >= '1' && *s <= '0'+NUM_SEARCH_COLORS) 1036 1.4 simonb { 1037 1.4 simonb st |= SRCH_SUBSEARCH(*s-'0'); 1038 1.4 simonb break; 1039 1.4 simonb } 1040 1.4 simonb parg.p_char = *s; 1041 1.4 simonb error("invalid search option '%c'", &parg); 1042 1.4 simonb return; 1043 1.4 simonb } 1044 1.4 simonb } 1045 1.4 simonb def_search_type = norm_search_type(st); 1046 1.4 simonb break; 1047 1.4 simonb case QUERY: 1048 1.4 simonb bp = buf; 1049 1.4 simonb if (def_search_type & SRCH_PAST_EOF) *bp++ = 'E'; 1050 1.4 simonb if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F'; 1051 1.4 simonb if (def_search_type & SRCH_NO_MOVE) *bp++ = 'K'; 1052 1.4 simonb if (def_search_type & SRCH_NO_MATCH) *bp++ = 'N'; 1053 1.4 simonb if (def_search_type & SRCH_NO_REGEX) *bp++ = 'R'; 1054 1.4 simonb if (def_search_type & SRCH_WRAP) *bp++ = 'W'; 1055 1.4 simonb for (i = 1; i <= NUM_SEARCH_COLORS; i++) 1056 1.4 simonb if (def_search_type & SRCH_SUBSEARCH(i)) 1057 1.4 simonb *bp++ = '0'+i; 1058 1.4 simonb if (bp == buf) 1059 1.4 simonb *bp++ = '-'; 1060 1.4 simonb *bp = '\0'; 1061 1.4 simonb parg.p_string = buf; 1062 1.4 simonb error("search options: %s", &parg); 1063 1.4 simonb break; 1064 1.4 simonb } 1065 1.4 simonb } 1066 1.4 simonb 1067 1.4 simonb #if LESSTEST 1068 1.4 simonb /* 1069 1.4 simonb * Handler for the --tty option. 1070 1.4 simonb */ 1071 1.4 simonb /*ARGSUSED*/ 1072 1.4 simonb public void opt_ttyin_name(int type, char *s) 1073 1.4 simonb { 1074 1.4 simonb switch (type) 1075 1.4 simonb { 1076 1.4 simonb case INIT: 1077 1.4 simonb ttyin_name = s; 1078 1.4 simonb is_tty = 1; 1079 1.4 simonb break; 1080 1.4 simonb } 1081 1.4 simonb } 1082 1.4 simonb #endif /*LESSTEST*/ 1083 1.4 simonb 1084 1.4 simonb public int chop_line(void) 1085 1.4 simonb { 1086 1.4 simonb return (chopline || header_cols > 0 || header_lines > 0); 1087 1.4 simonb } 1088 1.4 simonb 1089 1.4 simonb /* 1090 1.1 tron * Get the "screen window" size. 1091 1.1 tron */ 1092 1.4 simonb public int get_swindow(void) 1093 1.1 tron { 1094 1.1 tron if (swindow > 0) 1095 1.1 tron return (swindow); 1096 1.4 simonb return (sc_height - header_lines + swindow); 1097 1.1 tron } 1098 1.1 tron 1099