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