1 /*
2 * Copyright (C) 1984-2012 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, see the README file.
8 */
9
10
11 /*
12 * Handling functions for command line options.
13 *
14 * Most options are handled by the generic code in option.c.
15 * But all string options, and a few non-string options, require
16 * special handling specific to the particular option.
17 * This special processing is done by the "handling functions" in this file.
18 *
19 * Each handling function is passed a "type" and, if it is a string
20 * option, the string which should be "assigned" to the option.
21 * The type may be one of:
22 * INIT The option is being initialized from the command line.
23 * TOGGLE The option is being changed from within the program.
24 * QUERY The setting of the option is merely being queried.
25 */
26
27 #include "less.h"
28 #include "option.h"
29
30 extern int nbufs;
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 shift_count;
51 extern int shift_count_fraction;
52 extern int less_is_more;
53 #if LOGFILE
54 extern char *namelogfile;
55 extern int force_logfile;
56 extern int logfile;
57 #endif
58 #if TAGS
59 public char *tagoption = NULL;
60 extern char *tags;
61 #endif
62 #if MSDOS_COMPILER
63 extern int nm_fg_color, nm_bg_color;
64 extern int bo_fg_color, bo_bg_color;
65 extern int ul_fg_color, ul_bg_color;
66 extern int so_fg_color, so_bg_color;
67 extern int bl_fg_color, bl_bg_color;
68 #endif
69
70
71 #if LOGFILE
72 /*
73 * Handler for -o option.
74 */
75 public void
opt_o(type,s)76 opt_o(type, s)
77 int type;
78 char *s;
79 {
80 PARG parg;
81
82 if (secure)
83 {
84 error("log file support is not available", NULL_PARG);
85 return;
86 }
87 switch (type)
88 {
89 case INIT:
90 namelogfile = s;
91 break;
92 case TOGGLE:
93 if (ch_getflags() & CH_CANSEEK)
94 {
95 error("Input is not a pipe", NULL_PARG);
96 return;
97 }
98 if (logfile >= 0)
99 {
100 error("Log file is already in use", NULL_PARG);
101 return;
102 }
103 s = skipsp(s);
104 namelogfile = lglob(s);
105 use_logfile(namelogfile);
106 sync_logfile();
107 break;
108 case QUERY:
109 if (logfile < 0)
110 error("No log file", NULL_PARG);
111 else
112 {
113 parg.p_string = namelogfile;
114 error("Log file \"%s\"", &parg);
115 }
116 break;
117 }
118 }
119
120 /*
121 * Handler for -O option.
122 */
123 public void
opt__O(type,s)124 opt__O(type, s)
125 int type;
126 char *s;
127 {
128 force_logfile = TRUE;
129 opt_o(type, s);
130 }
131 #endif
132
133 /*
134 * Handlers for -j option.
135 */
136 public void
opt_j(type,s)137 opt_j(type, s)
138 int type;
139 char *s;
140 {
141 PARG parg;
142 char buf[16];
143 int len;
144 int err;
145
146 switch (type)
147 {
148 case INIT:
149 case TOGGLE:
150 if (*s == '.')
151 {
152 s++;
153 jump_sline_fraction = getfraction(&s, "j", &err);
154 if (err)
155 error("Invalid line fraction", NULL_PARG);
156 else
157 calc_jump_sline();
158 } else
159 {
160 int sline = getnum(&s, "j", &err);
161 if (err)
162 error("Invalid line number", NULL_PARG);
163 else
164 {
165 jump_sline = sline;
166 jump_sline_fraction = -1;
167 }
168 }
169 break;
170 case QUERY:
171 if (jump_sline_fraction < 0)
172 {
173 parg.p_int = jump_sline;
174 error("Position target at screen line %d", &parg);
175 } else
176 {
177
178 sprintf(buf, ".%06d", jump_sline_fraction);
179 len = strlen(buf);
180 while (len > 2 && buf[len-1] == '0')
181 len--;
182 buf[len] = '\0';
183 parg.p_string = buf;
184 error("Position target at screen position %s", &parg);
185 }
186 break;
187 }
188 }
189
190 public void
calc_jump_sline()191 calc_jump_sline()
192 {
193 if (jump_sline_fraction < 0)
194 return;
195 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
196 }
197
198 /*
199 * Handlers for -# option.
200 */
201 public void
opt_shift(type,s)202 opt_shift(type, s)
203 int type;
204 char *s;
205 {
206 PARG parg;
207 char buf[16];
208 int len;
209 int err;
210
211 switch (type)
212 {
213 case INIT:
214 case TOGGLE:
215 if (*s == '.')
216 {
217 s++;
218 shift_count_fraction = getfraction(&s, "#", &err);
219 if (err)
220 error("Invalid column fraction", NULL_PARG);
221 else
222 calc_shift_count();
223 } else
224 {
225 int hs = getnum(&s, "#", &err);
226 if (err)
227 error("Invalid column number", NULL_PARG);
228 else
229 {
230 shift_count = hs;
231 shift_count_fraction = -1;
232 }
233 }
234 break;
235 case QUERY:
236 if (shift_count_fraction < 0)
237 {
238 parg.p_int = shift_count;
239 error("Horizontal shift %d columns", &parg);
240 } else
241 {
242
243 sprintf(buf, ".%06d", shift_count_fraction);
244 len = strlen(buf);
245 while (len > 2 && buf[len-1] == '0')
246 len--;
247 buf[len] = '\0';
248 parg.p_string = buf;
249 error("Horizontal shift %s of screen width", &parg);
250 }
251 break;
252 }
253 }
254 public void
calc_shift_count()255 calc_shift_count()
256 {
257 if (shift_count_fraction < 0)
258 return;
259 shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
260 }
261
262 #if USERFILE
263 public void
opt_k(type,s)264 opt_k(type, s)
265 int type;
266 char *s;
267 {
268 PARG parg;
269
270 switch (type)
271 {
272 case INIT:
273 if (lesskey(s, 0))
274 {
275 parg.p_string = s;
276 error("Cannot use lesskey file \"%s\"", &parg);
277 }
278 break;
279 }
280 }
281 #endif
282
283 #if TAGS
284 /*
285 * Handler for -t option.
286 */
287 public void
opt_t(type,s)288 opt_t(type, s)
289 int type;
290 char *s;
291 {
292 IFILE save_ifile;
293 POSITION pos;
294
295 switch (type)
296 {
297 case INIT:
298 tagoption = s;
299 /* Do the rest in main() */
300 break;
301 case TOGGLE:
302 if (secure)
303 {
304 error("tags support is not available", NULL_PARG);
305 break;
306 }
307 findtag(skipsp(s));
308 save_ifile = save_curr_ifile();
309 /*
310 * Try to open the file containing the tag
311 * and search for the tag in that file.
312 */
313 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
314 {
315 /* Failed: reopen the old file. */
316 reedit_ifile(save_ifile);
317 break;
318 }
319 unsave_ifile(save_ifile);
320 jump_loc(pos, jump_sline);
321 break;
322 }
323 }
324
325 /*
326 * Handler for -T option.
327 */
328 public void
opt__T(type,s)329 opt__T(type, s)
330 int type;
331 char *s;
332 {
333 PARG parg;
334
335 switch (type)
336 {
337 case INIT:
338 tags = s;
339 break;
340 case TOGGLE:
341 s = skipsp(s);
342 tags = lglob(s);
343 break;
344 case QUERY:
345 parg.p_string = tags;
346 error("Tags file \"%s\"", &parg);
347 break;
348 }
349 }
350 #endif
351
352 /*
353 * Handler for -p option.
354 */
355 public void
opt_p(type,s)356 opt_p(type, s)
357 int type;
358 register char *s;
359 {
360 switch (type)
361 {
362 case INIT:
363 /*
364 * Unget a search command for the specified string.
365 * {{ This won't work if the "/" command is
366 * changed or invalidated by a .lesskey file. }}
367 */
368 plusoption = TRUE;
369 ungetsc(s);
370 /*
371 * In "more" mode, the -p argument is a command,
372 * not a search string, so we don't need a slash.
373 */
374 if (!less_is_more)
375 ungetsc("/");
376 break;
377 }
378 }
379
380 /*
381 * Handler for -P option.
382 */
383 public void
opt__P(type,s)384 opt__P(type, s)
385 int type;
386 register char *s;
387 {
388 register char **proto;
389 PARG parg;
390
391 switch (type)
392 {
393 case INIT:
394 case TOGGLE:
395 /*
396 * Figure out which prototype string should be changed.
397 */
398 switch (*s)
399 {
400 case 's': proto = &prproto[PR_SHORT]; s++; break;
401 case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
402 case 'M': proto = &prproto[PR_LONG]; s++; break;
403 case '=': proto = &eqproto; s++; break;
404 case 'h': proto = &hproto; s++; break;
405 case 'w': proto = &wproto; s++; break;
406 default: proto = &prproto[PR_SHORT]; break;
407 }
408 free(*proto);
409 *proto = save(s);
410 break;
411 case QUERY:
412 parg.p_string = prproto[pr_type];
413 error("%s", &parg);
414 break;
415 }
416 }
417
418 /*
419 * Handler for the -b option.
420 */
421 /*ARGSUSED*/
422 public void
opt_b(type,s)423 opt_b(type, s)
424 int type;
425 char *s;
426 {
427 switch (type)
428 {
429 case INIT:
430 case TOGGLE:
431 /*
432 * Set the new number of buffers.
433 */
434 ch_setbufspace(bufspace);
435 break;
436 case QUERY:
437 break;
438 }
439 }
440
441 /*
442 * Handler for the -i option.
443 */
444 /*ARGSUSED*/
445 public void
opt_i(type,s)446 opt_i(type, s)
447 int type;
448 char *s;
449 {
450 switch (type)
451 {
452 case TOGGLE:
453 chg_caseless();
454 break;
455 case QUERY:
456 case INIT:
457 break;
458 }
459 }
460
461 /*
462 * Handler for the -V option.
463 */
464 /*ARGSUSED*/
465 public void
opt__V(type,s)466 opt__V(type, s)
467 int type;
468 char *s;
469 {
470 switch (type)
471 {
472 case TOGGLE:
473 case QUERY:
474 dispversion();
475 break;
476 case INIT:
477 /*
478 * Force output to stdout per GNU standard for --version output.
479 */
480 any_display = 1;
481 putstr("less ");
482 putstr(version);
483 putstr(" (");
484 #if HAVE_GNU_REGEX
485 putstr("GNU ");
486 #endif
487 #if HAVE_POSIX_REGCOMP
488 putstr("POSIX ");
489 #endif
490 #if HAVE_PCRE
491 putstr("PCRE ");
492 #endif
493 #if HAVE_RE_COMP
494 putstr("BSD ");
495 #endif
496 #if HAVE_REGCMP
497 putstr("V8 ");
498 #endif
499 #if HAVE_V8_REGCOMP
500 putstr("Spencer V8 ");
501 #endif
502 #if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP
503 putstr("no ");
504 #endif
505 putstr("regular expressions)\n");
506 putstr("Copyright (C) 1984-2012 Mark Nudelman\n\n");
507 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
508 putstr("For information about the terms of redistribution,\n");
509 putstr("see the file named README in the less distribution.\n");
510 putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
511 quit(QUIT_OK);
512 break;
513 }
514 }
515
516 #if MSDOS_COMPILER
517 /*
518 * Parse an MSDOS color descriptor.
519 */
520 static void
colordesc(s,fg_color,bg_color)521 colordesc(s, fg_color, bg_color)
522 char *s;
523 int *fg_color;
524 int *bg_color;
525 {
526 int fg, bg;
527 int err;
528
529 fg = getnum(&s, "D", &err);
530 if (err)
531 {
532 error("Missing fg color in -D", NULL_PARG);
533 return;
534 }
535 if (*s != '.')
536 bg = nm_bg_color;
537 else
538 {
539 s++;
540 bg = getnum(&s, "D", &err);
541 if (err)
542 {
543 error("Missing bg color in -D", NULL_PARG);
544 return;
545 }
546 }
547 if (*s != '\0')
548 error("Extra characters at end of -D option", NULL_PARG);
549 *fg_color = fg;
550 *bg_color = bg;
551 }
552
553 /*
554 * Handler for the -D option.
555 */
556 /*ARGSUSED*/
557 public void
opt_D(type,s)558 opt_D(type, s)
559 int type;
560 char *s;
561 {
562 switch (type)
563 {
564 case INIT:
565 case TOGGLE:
566 switch (*s++)
567 {
568 case 'n':
569 colordesc(s, &nm_fg_color, &nm_bg_color);
570 break;
571 case 'd':
572 colordesc(s, &bo_fg_color, &bo_bg_color);
573 break;
574 case 'u':
575 colordesc(s, &ul_fg_color, &ul_bg_color);
576 break;
577 case 'k':
578 colordesc(s, &bl_fg_color, &bl_bg_color);
579 break;
580 case 's':
581 colordesc(s, &so_fg_color, &so_bg_color);
582 break;
583 default:
584 error("-D must be followed by n, d, u, k or s", NULL_PARG);
585 break;
586 }
587 if (type == TOGGLE)
588 {
589 at_enter(AT_STANDOUT);
590 at_exit();
591 }
592 break;
593 case QUERY:
594 break;
595 }
596 }
597 #endif
598
599 /*
600 * Handler for the -x option.
601 */
602 public void
opt_x(type,s)603 opt_x(type, s)
604 int type;
605 register char *s;
606 {
607 extern int tabstops[];
608 extern int ntabstops;
609 extern int tabdefault;
610 char msg[60+(4*TABSTOP_MAX)];
611 int i;
612 PARG p;
613
614 switch (type)
615 {
616 case INIT:
617 case TOGGLE:
618 /* Start at 1 because tabstops[0] is always zero. */
619 for (i = 1; i < TABSTOP_MAX; )
620 {
621 int n = 0;
622 s = skipsp(s);
623 while (*s >= '0' && *s <= '9')
624 n = (10 * n) + (*s++ - '0');
625 if (n > tabstops[i-1])
626 tabstops[i++] = n;
627 s = skipsp(s);
628 if (*s++ != ',')
629 break;
630 }
631 if (i < 2)
632 return;
633 ntabstops = i;
634 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
635 break;
636 case QUERY:
637 strcpy(msg, "Tab stops ");
638 if (ntabstops > 2)
639 {
640 for (i = 1; i < ntabstops; i++)
641 {
642 if (i > 1)
643 strcat(msg, ",");
644 sprintf(msg+strlen(msg), "%d", tabstops[i]);
645 }
646 sprintf(msg+strlen(msg), " and then ");
647 }
648 sprintf(msg+strlen(msg), "every %d spaces",
649 tabdefault);
650 p.p_string = msg;
651 error("%s", &p);
652 break;
653 }
654 }
655
656
657 /*
658 * Handler for the -" option.
659 */
660 public void
opt_quote(type,s)661 opt_quote(type, s)
662 int type;
663 register char *s;
664 {
665 char buf[3];
666 PARG parg;
667
668 switch (type)
669 {
670 case INIT:
671 case TOGGLE:
672 if (s[0] == '\0')
673 {
674 openquote = closequote = '\0';
675 break;
676 }
677 if (s[1] != '\0' && s[2] != '\0')
678 {
679 error("-\" must be followed by 1 or 2 chars", NULL_PARG);
680 return;
681 }
682 openquote = s[0];
683 if (s[1] == '\0')
684 closequote = openquote;
685 else
686 closequote = s[1];
687 break;
688 case QUERY:
689 buf[0] = openquote;
690 buf[1] = closequote;
691 buf[2] = '\0';
692 parg.p_string = buf;
693 error("quotes %s", &parg);
694 break;
695 }
696 }
697
698 /*
699 * "-?" means display a help message.
700 * If from the command line, exit immediately.
701 */
702 /*ARGSUSED*/
703 public void
opt_query(type,s)704 opt_query(type, s)
705 int type;
706 char *s;
707 {
708 switch (type)
709 {
710 case QUERY:
711 case TOGGLE:
712 error("Use \"h\" for help", NULL_PARG);
713 break;
714 case INIT:
715 dohelp = 1;
716 }
717 }
718
719 /*
720 * Get the "screen window" size.
721 */
722 public int
get_swindow()723 get_swindow()
724 {
725 if (swindow > 0)
726 return (swindow);
727 return (sc_height + swindow);
728 }
729
730