2 * Copyright (C) 1984-2022 Mark Nudelman
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.
7 * For more information, see the README file.
12 * Handling functions for command line options.
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.
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.
33 extern int plusoption;
40 extern char openquote;
41 extern char closequote;
42 extern char *prproto[];
46 extern char *every_first_cmd;
47 extern IFILE curr_ifile;
48 extern char version[];
49 extern int jump_sline;
50 extern long jump_sline_fraction;
51 extern int shift_count;
52 extern long shift_count_fraction;
53 extern char rscroll_char;
54 extern int rscroll_attr;
56 extern int wheel_lines;
57 extern int less_is_more;
58 extern int linenum_width;
59 extern int status_col_width;
61 extern int want_filesize;
62 extern int header_lines;
63 extern int header_cols;
64 extern int def_search_type;
67 extern char *namelogfile;
68 extern int force_logfile;
72 public char *tagoption = NULL;
77 extern char *ttyin_name;
78 extern int rstat_file;
81 extern int nm_fg_color, nm_bg_color;
82 extern int bo_fg_color, bo_bg_color;
83 extern int ul_fg_color, ul_bg_color;
84 extern int so_fg_color, so_bg_color;
85 extern int bl_fg_color, bl_bg_color;
87 #if MSDOS_COMPILER==WIN32C
88 #ifndef COMMON_LVB_UNDERSCORE
89 #define COMMON_LVB_UNDERSCORE 0x8000
97 * Handler for -o option.
109 error("log file support is not available", NULL_PARG);
115 namelogfile = save(s);
118 if (ch_getflags() & CH_CANSEEK)
120 error("Input is not a pipe", NULL_PARG);
125 error("Log file is already in use", NULL_PARG);
129 if (namelogfile != NULL)
132 namelogfile = shell_unquote(filename);
134 use_logfile(namelogfile);
139 error("No log file", NULL_PARG);
142 parg.p_string = namelogfile;
143 error("Log file \"%s\"", &parg);
150 * Handler for -O option.
157 force_logfile = TRUE;
163 * Handlers for -j option.
181 jump_sline_fraction = getfraction(&s, "j", &err);
183 error("Invalid line fraction", NULL_PARG);
188 int sline = getnum(&s, "j", &err);
190 error("Invalid line number", NULL_PARG);
194 jump_sline_fraction = -1;
199 if (jump_sline_fraction < 0)
201 parg.p_int = jump_sline;
202 error("Position target at screen line %d", &parg);
206 SNPRINTF1(buf, sizeof(buf), ".%06ld", jump_sline_fraction);
207 len = (int) strlen(buf);
208 while (len > 2 && buf[len-1] == '0')
212 error("Position target at screen position %s", &parg);
219 calc_jump_sline(VOID_PARAM)
221 if (jump_sline_fraction < 0)
223 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
227 * Handlers for -# option.
245 shift_count_fraction = getfraction(&s, "#", &err);
247 error("Invalid column fraction", NULL_PARG);
252 int hs = getnum(&s, "#", &err);
254 error("Invalid column number", NULL_PARG);
258 shift_count_fraction = -1;
263 if (shift_count_fraction < 0)
265 parg.p_int = shift_count;
266 error("Horizontal shift %d columns", &parg);
270 SNPRINTF1(buf, sizeof(buf), ".%06ld", shift_count_fraction);
271 len = (int) strlen(buf);
272 while (len > 2 && buf[len-1] == '0')
276 error("Horizontal shift %s of screen width", &parg);
283 calc_shift_count(VOID_PARAM)
285 if (shift_count_fraction < 0)
287 shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
304 error("Cannot use lesskey file \"%s\"", &parg);
321 if (lesskey_src(s, 0))
324 error("Cannot use lesskey source file \"%s\"", &parg);
329 #endif /* HAVE_LESSKEYSRC */
330 #endif /* USERFILE */
334 * Handler for -t option.
348 /* Do the rest in main() */
353 error("tags support is not available", NULL_PARG);
357 save_ifile = save_curr_ifile();
359 * Try to open the file containing the tag
360 * and search for the tag in that file.
362 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
364 /* Failed: reopen the old file. */
365 reedit_ifile(save_ifile);
368 unsave_ifile(save_ifile);
369 jump_loc(pos, jump_sline);
375 * Handler for -T option.
392 if (tags != NULL && tags != ztags)
395 tags = shell_unquote(filename);
399 parg.p_string = tags;
400 error("Tags file \"%s\"", &parg);
407 * Handler for -p option.
418 * Unget a command for the specified string.
423 * In "more" mode, the -p argument is a command,
424 * not a search string, so we don't need a slash.
426 every_first_cmd = save(s);
431 * {{ This won't work if the "/" command is
432 * changed or invalidated by a .lesskey file. }}
436 ungetcc_back(CHAR_END_COMMAND);
443 * Handler for -P option.
458 * Figure out which prototype string should be changed.
462 case 's': proto = &prproto[PR_SHORT]; s++; break;
463 case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
464 case 'M': proto = &prproto[PR_LONG]; s++; break;
465 case '=': proto = &eqproto; s++; break;
466 case 'h': proto = &hproto; s++; break;
467 case 'w': proto = &wproto; s++; break;
468 default: proto = &prproto[PR_SHORT]; break;
474 parg.p_string = prproto[pr_type];
481 * Handler for the -b option.
494 * Set the new number of buffers.
496 ch_setbufspace(bufspace);
504 * Handler for the -i option.
524 * Handler for the -V option.
539 set_output(1); /* Force output to stdout per GNU standard for --version output. */
543 putstr(pattern_lib_name());
544 putstr(" regular expressions)\n");
546 char constant *copyright =
547 "Copyright (C) 1984-2022 Mark Nudelman\n\n";
550 if (version[strlen(version)-1] == 'x')
552 putstr("** This is an EXPERIMENTAL build of the 'less' software,\n");
553 putstr("** and may not function correctly.\n");
554 putstr("** Obtain release builds from the web page below.\n\n");
556 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
557 putstr("For information about the terms of redistribution,\n");
558 putstr("see the file named README in the less distribution.\n");
559 putstr("Home page: https://greenwoodsoftware.com/less\n");
567 * Parse an MSDOS color descriptor.
570 colordesc(s, fg_color, bg_color)
576 #if MSDOS_COMPILER==WIN32C
581 ul = COMMON_LVB_UNDERSCORE;
585 *fg_color = nm_fg_color | ul;
586 *bg_color = nm_bg_color;
591 if (parse_color(s, &fg, &bg) == CT_NULL)
595 error("Invalid color string \"%s\"", &p);
598 if (fg == CV_NOCHANGE)
600 if (bg == CV_NOCHANGE)
602 #if MSDOS_COMPILER==WIN32C
612 color_from_namechar(namechar)
617 case 'B': return AT_COLOR_BIN;
618 case 'C': return AT_COLOR_CTRL;
619 case 'E': return AT_COLOR_ERROR;
620 case 'H': return AT_COLOR_HEADER;
621 case 'M': return AT_COLOR_MARK;
622 case 'N': return AT_COLOR_LINENUM;
623 case 'P': return AT_COLOR_PROMPT;
624 case 'R': return AT_COLOR_RSCROLL;
625 case 'S': return AT_COLOR_SEARCH;
626 case 'W': case 'A': return AT_COLOR_ATTN;
627 case 'n': return AT_NORMAL;
628 case 's': return AT_STANDOUT;
629 case 'd': return AT_BOLD;
630 case 'u': return AT_UNDERLINE;
631 case 'k': return AT_BLINK;
637 * Handler for the -D option.
655 sgr_mode = !sgr_mode;
659 attr = color_from_namechar(s[0]);
663 error("Invalid color specifier '%c'", &p);
666 if (!use_color && (attr & AT_COLOR))
668 error("Set --use-color before changing colors", NULL_PARG);
673 if (!(attr & AT_COLOR))
678 colordesc(s, &nm_fg_color, &nm_bg_color);
681 colordesc(s, &bo_fg_color, &bo_bg_color);
684 colordesc(s, &ul_fg_color, &ul_bg_color);
687 colordesc(s, &bl_fg_color, &bl_bg_color);
690 colordesc(s, &so_fg_color, &so_bg_color);
695 at_enter(AT_STANDOUT);
700 if (set_color_map(attr, s) < 0)
703 error("Invalid color string \"%s\"", &p);
709 p.p_string = (sgr_mode) ? "on" : "off";
710 error("SGR mode is %s", &p);
717 * Handler for the -x option.
724 extern int tabstops[];
725 extern int ntabstops;
726 extern int tabdefault;
727 char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)];
735 /* Start at 1 because tabstops[0] is always zero. */
736 for (i = 1; i < TABSTOP_MAX; )
740 while (*s >= '0' && *s <= '9')
741 n = (10 * n) + (*s++ - '0');
742 if (n > tabstops[i-1])
751 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
754 strcpy(msg, "Tab stops ");
757 for (i = 1; i < ntabstops; i++)
761 sprintf(msg+strlen(msg), "%d", tabstops[i]);
763 sprintf(msg+strlen(msg), " and then ");
765 sprintf(msg+strlen(msg), "every %d spaces",
775 * Handler for the -" option.
791 openquote = closequote = '\0';
794 if (s[1] != '\0' && s[2] != '\0')
796 error("-\" must be followed by 1 or 2 chars", NULL_PARG);
801 closequote = openquote;
810 error("quotes %s", &parg);
816 * Handler for the --rscroll option.
831 int attr = AT_STANDOUT;
832 setfmt(s, &fmt, &attr, "*s>");
833 if (strcmp(fmt, "-") == 0)
838 rscroll_char = *fmt ? *fmt : '>';
839 rscroll_attr = attr|AT_COLOR_RSCROLL;
843 p.p_string = rscroll_char ? prchar(rscroll_char) : "-";
844 error("rscroll char is %s", &p);
850 * "-?" means display a help message.
851 * If from the command line, exit immediately.
863 error("Use \"h\" for help", NULL_PARG);
871 * Handler for the --mouse option.
875 opt_mousecap(type, s)
882 if (mousecap == OPT_OFF)
894 * Handler for the --wheel-lines option.
898 opt_wheel_lines(type, s)
906 if (wheel_lines <= 0)
907 wheel_lines = default_wheel_lines();
915 * Handler for the --line-number-width option.
919 opt_linenum_width(type, s)
929 if (linenum_width > MAX_LINENUM_WIDTH)
931 parg.p_int = MAX_LINENUM_WIDTH;
932 error("Line number width must not be larger than %d", &parg);
933 linenum_width = MIN_LINENUM_WIDTH;
942 * Handler for the --status-column-width option.
946 opt_status_col_width(type, s)
956 if (status_col_width > MAX_STATUSCOL_WIDTH)
958 parg.p_int = MAX_STATUSCOL_WIDTH;
959 error("Status column width must not be larger than %d", &parg);
960 status_col_width = 2;
969 * Handler for the --file-size option.
973 opt_filesize(type, s)
981 if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION)
990 * Handler for the --header option.
1005 n = getnum(&s, "header", &err);
1007 error("invalid number of lines", NULL_PARG);
1015 n = getnum(&s, "header", &err);
1017 error("invalid number of columns", NULL_PARG);
1025 char buf[2*INT_STRLEN_BOUND(int)+2];
1027 SNPRINTF2(buf, sizeof(buf), "%d,%d", header_lines, header_cols);
1028 parg.p_string = buf;
1029 error("header (lines,columns) is %s", &parg);
1036 * Handler for the --search-options option.
1040 opt_search_type(type, s)
1054 for (; *s != '\0'; s++)
1058 case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF; break;
1059 case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break;
1060 case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE; break;
1061 case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH; break;
1062 case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX; break;
1063 case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP; break;
1064 case '-': st = 0; break;
1068 error("invalid search option '%c'", &parg);
1072 def_search_type = norm_search_type(st);
1076 if (def_search_type & SRCH_PAST_EOF) *bp++ = 'E';
1077 if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F';
1078 if (def_search_type & SRCH_NO_MOVE) *bp++ = 'K';
1079 if (def_search_type & SRCH_NO_MATCH) *bp++ = 'N';
1080 if (def_search_type & SRCH_NO_REGEX) *bp++ = 'R';
1081 if (def_search_type & SRCH_WRAP) *bp++ = 'W';
1085 parg.p_string = buf;
1086 error("search options: %s", &parg);
1093 * Handler for the --tty option.
1097 opt_ttyin_name(type, s)
1111 * Handler for the --rstat option.
1122 rstat_file = open(s, O_WRONLY|O_CREAT, 0664);
1127 error("Cannot create rstat file \"%s\"", &parg);
1135 chop_line(VOID_PARAM)
1137 return (chopline || header_cols > 0 || header_lines > 0);
1141 * Get the "screen window" size.
1144 get_swindow(VOID_PARAM)
1148 return (sc_height - header_lines + swindow);