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