1 /*
2 * Copyright (C) 1984-2025 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 * The option table.
13 */
14
15 #include "less.h"
16 #include "option.h"
17
18 /*
19 * Variables controlled by command line options.
20 */
21 public int quiet; /* Should we suppress the audible bell? */
22 public int no_vbell; /* Should we suppress the visual bell? */
23 public int how_search; /* Where should forward searches start? */
24 public int top_scroll; /* Repaint screen from top?
25 (alternative is scroll from bottom) */
26 public int pr_type; /* Type of prompt (short, medium, long) */
27 public int bs_mode; /* How to process backspaces */
28 public int know_dumb; /* Don't complain about dumb terminals */
29 public int quit_at_eof; /* Quit after hitting end of file twice */
30 public int quit_if_one_screen; /* Quit if EOF on first screen */
31 public int squeeze; /* Squeeze multiple blank lines into one */
32 public int tabstop; /* Tab settings */
33 public int back_scroll; /* Repaint screen on backwards movement */
34 public int forw_scroll; /* Repaint screen on forward movement */
35 public int caseless; /* Do "caseless" searches */
36 public int linenums; /* Use line numbers */
37 public int autobuf; /* Automatically allocate buffers as needed */
38 public int bufspace; /* Max buffer space per file (K) */
39 public int ctldisp; /* Send control chars to screen untranslated */
40 public int force_open; /* Open the file even if not regular file */
41 public int swindow; /* Size of scrolling window */
42 public int jump_sline; /* Screen line of "jump target" */
43 public long jump_sline_fraction = -1;
44 public int shift_count; /* Number of positions to shift horizontally */
45 public long shift_count_fraction = -1;
46 public int chopline; /* Truncate displayed lines at screen width */
47 public int wordwrap; /* Wrap lines at space */
48 public int no_init; /* Disable sending ti/te termcap strings */
49 public int no_keypad; /* Disable sending ks/ke termcap strings */
50 public int twiddle; /* Show tildes after EOF */
51 public int show_attn; /* Hilite first unread line */
52 public int status_col; /* Display a status column */
53 public int use_lessopen; /* Use the LESSOPEN filter */
54 public int quit_on_intr; /* Quit on interrupt */
55 public int follow_mode; /* F cmd Follows file desc or file name? */
56 public int oldbot; /* Old bottom of screen behavior {{REMOVE}} */
57 public int opt_use_backslash; /* Use backslash escaping in option parsing */
58 public LWCHAR rscroll_char; /* Char which marks chopped lines with -S */
59 public int rscroll_attr; /* Attribute of rscroll_char */
60 public int no_hist_dups; /* Remove dups from history list */
61 public int mousecap; /* Allow mouse for scrolling */
62 public int wheel_lines; /* Number of lines to scroll on mouse wheel scroll */
63 public int perma_marks; /* Save marks in history file */
64 public int linenum_width; /* Width of line numbers */
65 public int status_col_width; /* Width of status column */
66 public int incr_search; /* Incremental search */
67 public int use_color; /* Use UI color */
68 public int want_filesize; /* Scan to EOF if necessary to get file size */
69 public int status_line; /* Highlight entire marked lines */
70 public int header_lines; /* Freeze header lines at top of screen */
71 public int header_cols; /* Freeze header columns at left of screen */
72 public int nonum_headers; /* Don't give headers line numbers */
73 public int nosearch_header_lines = 0; /* Don't search in header lines */
74 public int nosearch_header_cols = 0; /* Don't search in header columns */
75 public int redraw_on_quit; /* Redraw last screen after term deinit */
76 public int def_search_type; /* */
77 public int exit_F_on_close; /* Exit F command when input closes */
78 public int modelines; /* Lines to read looking for modelines */
79 public int show_preproc_error; /* Display msg when preproc exits with error */
80 public int proc_backspace; /* Special handling of backspace */
81 public int proc_tab; /* Special handling of tab */
82 public int proc_return; /* Special handling of carriage return */
83 public int match_shift; /* Extra horizontal shift on search match */
84 public int no_paste; /* Don't accept pasted input */
85 public int no_edit_warn; /* Don't warn when editing a LESSOPENed file */
86 public int stop_on_form_feed; /* Stop scrolling on a line starting with form feed */
87 public long match_shift_fraction = NUM_FRAC_DENOM/2; /* 1/2 of screen width */
88 public char intr_char = CONTROL('X'); /* Char to interrupt reads */
89 #if HILITE_SEARCH
90 public int hilite_search; /* Highlight matched search patterns? */
91 #endif
92
93 public int less_is_more = 0; /* Make compatible with POSIX more */
94
95 /*
96 * Long option names.
97 */
98 static struct optname a_optname = { "search-skip-screen", NULL };
99 static struct optname b_optname = { "buffers", NULL };
100 static struct optname B__optname = { "auto-buffers", NULL };
101 static struct optname c_optname = { "clear-screen", NULL };
102 static struct optname d_optname = { "dumb", NULL };
103 static struct optname D__optname = { "color", NULL };
104 static struct optname e_optname = { "quit-at-eof", NULL };
105 static struct optname f_optname = { "force", NULL };
106 static struct optname F__optname = { "quit-if-one-screen", NULL };
107 #if HILITE_SEARCH
108 static struct optname g_optname = { "hilite-search", NULL };
109 #endif
110 static struct optname h_optname = { "max-back-scroll", NULL };
111 static struct optname i_optname = { "ignore-case", NULL };
112 static struct optname j_optname = { "jump-target", NULL };
113 static struct optname J__optname = { "status-column", NULL };
114 #if USERFILE
115 static struct optname k_optname = { "lesskey-file", NULL };
116 #if HAVE_LESSKEYSRC
117 static struct optname ks_optname = { "lesskey-src", NULL };
118 static struct optname kc_optname = { "lesskey-content", NULL };
119 #endif /* HAVE_LESSKEYSRC */
120 #endif
121 static struct optname K__optname = { "quit-on-intr", NULL };
122 static struct optname L__optname = { "no-lessopen", NULL };
123 static struct optname m_optname = { "long-prompt", NULL };
124 static struct optname n_optname = { "line-numbers", NULL };
125 #if LOGFILE
126 static struct optname o_optname = { "log-file", NULL };
127 static struct optname O__optname = { "LOG-FILE", NULL };
128 #endif
129 static struct optname p_optname = { "pattern", NULL };
130 static struct optname P__optname = { "prompt", NULL };
131 static struct optname q2_optname = { "silent", NULL };
132 static struct optname q_optname = { "quiet", &q2_optname };
133 static struct optname r_optname = { "raw-control-chars", NULL };
134 static struct optname s_optname = { "squeeze-blank-lines", NULL };
135 static struct optname S__optname = { "chop-long-lines", NULL };
136 #if TAGS
137 static struct optname t_optname = { "tag", NULL };
138 static struct optname T__optname = { "tag-file", NULL };
139 #endif
140 static struct optname u_optname = { "underline-special", NULL };
141 static struct optname V__optname = { "version", NULL };
142 static struct optname w_optname = { "hilite-unread", NULL };
143 static struct optname x_optname = { "tabs", NULL };
144 static struct optname X__optname = { "no-init", NULL };
145 static struct optname y_optname = { "max-forw-scroll", NULL };
146 static struct optname z_optname = { "window", NULL };
147 static struct optname quote_optname = { "quotes", NULL };
148 static struct optname tilde_optname = { "tilde", NULL };
149 static struct optname query_optname = { "help", NULL };
150 static struct optname pound_optname = { "shift", NULL };
151 static struct optname keypad_optname = { "no-keypad", NULL };
152 static struct optname oldbot_optname = { "old-bot", NULL };
153 static struct optname follow_optname = { "follow-name", NULL };
154 static struct optname use_backslash_optname = { "use-backslash", NULL };
155 static struct optname rscroll_optname = { "rscroll", NULL };
156 static struct optname nohistdups_optname = { "no-histdups", NULL };
157 static struct optname mousecap_optname = { "mouse", NULL };
158 static struct optname wheel_lines_optname = { "wheel-lines", NULL };
159 static struct optname perma_marks_optname = { "save-marks", NULL };
160 static struct optname linenum_width_optname = { "line-num-width", NULL };
161 static struct optname status_col_width_optname = { "status-col-width", NULL };
162 static struct optname incr_search_optname = { "incsearch", NULL };
163 static struct optname use_color_optname = { "use-color", NULL };
164 static struct optname want_filesize_optname = { "file-size", NULL };
165 static struct optname status_line_optname = { "status-line", NULL };
166 static struct optname header_optname = { "header", NULL };
167 static struct optname no_paste_optname = { "no-paste", NULL };
168 static struct optname form_feed_optname = { "form-feed", NULL };
169 static struct optname no_edit_warn_optname2 = { "no-warn-edit", NULL };
170 static struct optname no_edit_warn_optname = { "no-edit-warn", &no_edit_warn_optname2 };
171 static struct optname nonum_headers_optname = { "no-number-headers", NULL };
172 static struct optname nosearch_headers_optname = { "no-search-headers", NULL };
173 static struct optname nosearch_header_lines_optname = { "no-search-header-lines", NULL };
174 static struct optname nosearch_header_cols_optname = { "no-search-header-columns", NULL };
175 static struct optname redraw_on_quit_optname = { "redraw-on-quit", NULL };
176 static struct optname search_type_optname = { "search-options", NULL };
177 static struct optname exit_F_on_close_optname = { "exit-follow-on-close", NULL };
178 static struct optname modelines_optname = { "modelines", NULL };
179 static struct optname no_vbell_optname = { "no-vbell", NULL };
180 static struct optname intr_optname = { "intr", NULL };
181 static struct optname wordwrap_optname = { "wordwrap", NULL };
182 static struct optname show_preproc_error_optname = { "show-preproc-errors", NULL };
183 static struct optname proc_backspace_optname = { "proc-backspace", NULL };
184 static struct optname proc_tab_optname = { "proc-tab", NULL };
185 static struct optname proc_return_optname = { "proc-return", NULL };
186 static struct optname match_shift_optname = { "match-shift", NULL };
187 #if LESSTEST
188 static struct optname ttyin_name_optname = { "tty", NULL };
189 #endif /*LESSTEST*/
190
191
192 /*
193 * Table of all options and their semantics.
194 *
195 * For BOOL and TRIPLE options, odesc[0], odesc[1], odesc[2] are
196 * the description of the option when set to 0, 1 or 2, respectively.
197 * For NUMBER options, odesc[0] is the prompt to use when entering
198 * a new value, and odesc[1] is the description, which should contain
199 * one %d which is replaced by the value of the number.
200 * For STRING options, odesc[0] is the prompt to use when entering
201 * a new value, and odesc[1], if not NULL, is the set of characters
202 * that are valid in the string.
203 */
204 static struct loption option[] =
205 {
206 { 'a', &a_optname,
207 O_TRIPLE, OPT_ONPLUS, &how_search, NULL,
208 {
209 "Search includes displayed screen",
210 "Search skips displayed screen",
211 "Search includes all of displayed screen"
212 }
213 },
214
215 { 'b', &b_optname,
216 O_NUMBER|O_INIT_HANDLER, 64, &bufspace, opt_b,
217 {
218 "Max buffer space per file (K): ",
219 "Max buffer space per file: %dK",
220 NULL
221 }
222 },
223 { 'B', &B__optname,
224 O_BOOL, OPT_ON, &autobuf, NULL,
225 {
226 "Don't automatically allocate buffers",
227 "Automatically allocate buffers when needed",
228 NULL
229 }
230 },
231 { 'c', &c_optname,
232 O_TRIPLE, OPT_OFF, &top_scroll, NULL,
233 {
234 "Repaint by scrolling from bottom of screen",
235 "Repaint by painting from top of screen",
236 "Repaint by painting from top of screen"
237 }
238 },
239 { 'd', &d_optname,
240 O_BOOL|O_NO_TOGGLE, OPT_OFF, &know_dumb, NULL,
241 {
242 "Assume intelligent terminal",
243 "Assume dumb terminal",
244 NULL
245 }
246 },
247 { 'D', &D__optname,
248 O_STRING|O_REPAINT|O_NO_QUERY, 0, NULL, opt_D,
249 { "color desc: ", "s", NULL }
250 },
251 { 'e', &e_optname,
252 O_TRIPLE, OPT_OFF, &quit_at_eof, NULL,
253 {
254 "Don't quit at end-of-file",
255 "Quit at end-of-file",
256 "Quit immediately at end-of-file"
257 }
258 },
259 { 'f', &f_optname,
260 O_BOOL, OPT_OFF, &force_open, NULL,
261 {
262 "Open only regular files",
263 "Open even non-regular files",
264 NULL
265 }
266 },
267 { 'F', &F__optname,
268 O_BOOL, OPT_OFF, &quit_if_one_screen, NULL,
269 {
270 "Don't quit if end-of-file on first screen",
271 "Quit if end-of-file on first screen",
272 NULL
273 }
274 },
275 #if HILITE_SEARCH
276 { 'g', &g_optname,
277 O_TRIPLE|O_HL_REPAINT, OPT_ONPLUS, &hilite_search, NULL,
278 {
279 "Don't highlight search matches",
280 "Highlight matches for previous search only",
281 "Highlight all matches for previous search pattern",
282 }
283 },
284 #endif
285 { 'h', &h_optname,
286 O_NUMBER, -1, &back_scroll, NULL,
287 {
288 "Backwards scroll limit: ",
289 "Backwards scroll limit is %d lines",
290 NULL
291 }
292 },
293 { 'i', &i_optname,
294 O_TRIPLE|O_HL_REPAINT, OPT_OFF, &caseless, opt_i,
295 {
296 "Case is significant in searches",
297 "Ignore case in searches",
298 "Ignore case in searches and in patterns"
299 }
300 },
301 { 'j', &j_optname,
302 O_STRING, 0, NULL, opt_j,
303 {
304 "Target line: ",
305 "-.d",
306 NULL
307 }
308 },
309 { 'J', &J__optname,
310 O_BOOL|O_REPAINT, OPT_OFF, &status_col, NULL,
311 {
312 "Don't display a status column",
313 "Display a status column",
314 NULL
315 }
316 },
317 #if USERFILE
318 { 'k', &k_optname,
319 O_STRING|O_NO_TOGGLE|O_NO_QUERY, 0, NULL, opt_k,
320 { NULL, NULL, NULL }
321 },
322 #if HAVE_LESSKEYSRC
323 { OLETTER_NONE, &kc_optname,
324 O_STRING|O_NO_TOGGLE|O_NO_QUERY, 0, NULL, opt_kc,
325 { NULL, NULL, NULL }
326 },
327 { OLETTER_NONE, &ks_optname,
328 O_STRING|O_NO_TOGGLE|O_NO_QUERY, 0, NULL, opt_ks,
329 { NULL, NULL, NULL }
330 },
331 #endif /* HAVE_LESSKEYSRC */
332 #endif
333 { 'K', &K__optname,
334 O_BOOL, OPT_OFF, &quit_on_intr, NULL,
335 {
336 "Interrupt (ctrl-C) returns to prompt",
337 "Interrupt (ctrl-C) exits less",
338 NULL
339 }
340 },
341 { 'L', &L__optname,
342 O_BOOL, OPT_ON, &use_lessopen, NULL,
343 {
344 "Don't use the LESSOPEN filter",
345 "Use the LESSOPEN filter",
346 NULL
347 }
348 },
349 { 'm', &m_optname,
350 O_TRIPLE, OPT_OFF, &pr_type, NULL,
351 {
352 "Short prompt",
353 "Medium prompt",
354 "Long prompt"
355 }
356 },
357 { 'n', &n_optname,
358 O_TRIPLE|O_REPAINT, OPT_ON, &linenums, NULL,
359 {
360 "Don't use line numbers",
361 "Use line numbers",
362 "Constantly display line numbers"
363 }
364 },
365 #if LOGFILE
366 { 'o', &o_optname,
367 O_STRING, 0, NULL, opt_o,
368 { "log file: ", NULL, NULL }
369 },
370 { 'O', &O__optname,
371 O_STRING, 0, NULL, opt__O,
372 { "Log file: ", NULL, NULL }
373 },
374 #endif
375 { 'p', &p_optname,
376 O_STRING|O_NO_TOGGLE|O_NO_QUERY, 0, NULL, opt_p,
377 { NULL, NULL, NULL }
378 },
379 { 'P', &P__optname,
380 O_STRING, 0, NULL, opt__P,
381 { "prompt: ", NULL, NULL }
382 },
383 { 'q', &q_optname,
384 O_TRIPLE, OPT_OFF, &quiet, NULL,
385 {
386 "Ring the bell for errors AND at eof/bof",
387 "Ring the bell for errors but not at eof/bof",
388 "Never ring the bell"
389 }
390 },
391 { 'r', &r_optname,
392 O_TRIPLE|O_REPAINT, OPT_OFF, &ctldisp, NULL,
393 {
394 "Display control characters as ^X",
395 "Display control characters directly (not recommended)",
396 "Display ANSI sequences directly, other control characters as ^X"
397 }
398 },
399 { 's', &s_optname,
400 O_BOOL|O_REPAINT, OPT_OFF, &squeeze, NULL,
401 {
402 "Display all blank lines",
403 "Squeeze multiple blank lines",
404 NULL
405 }
406 },
407 { 'S', &S__optname,
408 O_BOOL|O_REPAINT, OPT_OFF, &chopline, opt__S,
409 {
410 "Fold long lines",
411 "Chop long lines",
412 NULL
413 }
414 },
415 #if TAGS
416 { 't', &t_optname,
417 O_STRING|O_NO_QUERY, 0, NULL, opt_t,
418 { "tag: ", NULL, NULL }
419 },
420 { 'T', &T__optname,
421 O_STRING, 0, NULL, opt__T,
422 { "tags file: ", NULL, NULL }
423 },
424 #endif
425 { 'u', &u_optname,
426 O_TRIPLE|O_REPAINT|O_HL_REPAINT, OPT_OFF, &bs_mode, NULL,
427 {
428 "Display underlined text in underline mode",
429 "Backspaces cause overstrike",
430 "Print backspace as ^H"
431 }
432 },
433 { 'V', &V__optname,
434 O_NOVAR, 0, NULL, opt__V,
435 { NULL, NULL, NULL }
436 },
437 { 'w', &w_optname,
438 O_TRIPLE|O_REPAINT, OPT_OFF, &show_attn, NULL,
439 {
440 "Don't highlight first unread line",
441 "Highlight first unread line after forward-screen",
442 "Highlight first unread line after any forward movement",
443 }
444 },
445 { 'x', &x_optname,
446 O_STRING|O_REPAINT, 0, NULL, opt_x,
447 {
448 "Tab stops: ",
449 "d,",
450 NULL
451 }
452 },
453 { 'X', &X__optname,
454 O_BOOL|O_NO_TOGGLE, OPT_OFF, &no_init, NULL,
455 {
456 "Send init/deinit strings to terminal",
457 "Don't use init/deinit strings",
458 NULL
459 }
460 },
461 { 'y', &y_optname,
462 O_NUMBER, -1, &forw_scroll, NULL,
463 {
464 "Forward scroll limit: ",
465 "Forward scroll limit is %d lines",
466 NULL
467 }
468 },
469 { 'z', &z_optname,
470 O_NUMBER, -1, &swindow, NULL,
471 {
472 "Scroll window size: ",
473 "Scroll window size is %d lines",
474 NULL
475 }
476 },
477 { '"', "e_optname,
478 O_STRING, 0, NULL, opt_quote,
479 { "quotes: ", "s", NULL }
480 },
481 { '~', &tilde_optname,
482 O_BOOL|O_REPAINT, OPT_ON, &twiddle, NULL,
483 {
484 "Don't show tildes after end of file",
485 "Show tildes after end of file",
486 NULL
487 }
488 },
489 { '?', &query_optname,
490 O_NOVAR, 0, NULL, opt_query,
491 { NULL, NULL, NULL }
492 },
493 { '#', £_optname,
494 O_STRING, 0, NULL, opt_shift,
495 {
496 "Horizontal shift: ",
497 ".d",
498 NULL
499 }
500 },
501 { OLETTER_NONE, &keypad_optname,
502 O_BOOL|O_NO_TOGGLE, OPT_OFF, &no_keypad, NULL,
503 {
504 "Use keypad mode",
505 "Don't use keypad mode",
506 NULL
507 }
508 },
509 { OLETTER_NONE, &oldbot_optname,
510 O_BOOL, OPT_OFF, &oldbot, NULL,
511 {
512 "Use new bottom of screen behavior",
513 "Use old bottom of screen behavior",
514 NULL
515 }
516 },
517 { OLETTER_NONE, &follow_optname,
518 O_BOOL, FOLLOW_DESC, &follow_mode, NULL,
519 {
520 "F command follows file descriptor",
521 "F command follows file name",
522 NULL
523 }
524 },
525 { OLETTER_NONE, &use_backslash_optname,
526 O_BOOL, OPT_OFF, &opt_use_backslash, NULL,
527 {
528 "Use backslash escaping in command line parameters",
529 "Don't use backslash escaping in command line parameters",
530 NULL
531 }
532 },
533 { OLETTER_NONE, &rscroll_optname,
534 O_STRING|O_REPAINT|O_INIT_HANDLER, 0, NULL, opt_rscroll,
535 { "rscroll character: ", "s", NULL }
536 },
537 { OLETTER_NONE, &nohistdups_optname,
538 O_BOOL, OPT_OFF, &no_hist_dups, NULL,
539 {
540 "Allow duplicates in history list",
541 "Remove duplicates from history list",
542 NULL
543 }
544 },
545 { OLETTER_NONE, &mousecap_optname,
546 O_TRIPLE, OPT_OFF, &mousecap, opt_mousecap,
547 {
548 "Ignore mouse input",
549 "Use the mouse for scrolling",
550 "Use the mouse for scrolling (reverse)"
551 }
552 },
553 { OLETTER_NONE, &wheel_lines_optname,
554 O_NUMBER|O_INIT_HANDLER, 0, &wheel_lines, opt_wheel_lines,
555 {
556 "Lines to scroll on mouse wheel: ",
557 "Scroll %d line(s) on mouse wheel",
558 NULL
559 }
560 },
561 { OLETTER_NONE, &perma_marks_optname,
562 O_BOOL, OPT_OFF, &perma_marks, NULL,
563 {
564 "Don't save marks in history file",
565 "Save marks in history file",
566 NULL
567 }
568 },
569 { OLETTER_NONE, &linenum_width_optname,
570 O_NUMBER|O_REPAINT, MIN_LINENUM_WIDTH, &linenum_width, opt_linenum_width,
571 {
572 "Line number width: ",
573 "Line number width is %d chars",
574 NULL
575 }
576 },
577 { OLETTER_NONE, &status_col_width_optname,
578 O_NUMBER|O_REPAINT, 2, &status_col_width, opt_status_col_width,
579 {
580 "Status column width: ",
581 "Status column width is %d chars",
582 NULL
583 }
584 },
585 { OLETTER_NONE, &incr_search_optname,
586 O_BOOL, OPT_OFF, &incr_search, NULL,
587 {
588 "Incremental search is off",
589 "Incremental search is on",
590 NULL
591 }
592 },
593 { OLETTER_NONE, &use_color_optname,
594 O_BOOL|O_REPAINT, OPT_OFF, &use_color, NULL,
595 {
596 "Don't use color",
597 "Use color",
598 NULL
599 }
600 },
601 { OLETTER_NONE, &want_filesize_optname,
602 O_BOOL|O_REPAINT, OPT_OFF, &want_filesize, opt_filesize,
603 {
604 "Don't get size of each file",
605 "Get size of each file",
606 NULL
607 }
608 },
609 { OLETTER_NONE, &status_line_optname,
610 O_BOOL|O_REPAINT, OPT_OFF, &status_line, NULL,
611 {
612 "Don't color each line with its status column color",
613 "Color each line with its status column color",
614 NULL
615 }
616 },
617 { OLETTER_NONE, &header_optname,
618 O_STRING|O_REPAINT, 0, NULL, opt_header,
619 { "Header lines: ", "d,", NULL }
620 },
621 { OLETTER_NONE, &no_paste_optname,
622 O_BOOL, OPT_OFF, &no_paste, opt_no_paste,
623 {
624 "Accept pasted input",
625 "Ignore pasted input",
626 NULL
627 }
628 },
629 { OLETTER_NONE, &form_feed_optname,
630 O_BOOL, OPT_OFF, &stop_on_form_feed, NULL,
631 {
632 "Don't stop on form feed",
633 "Stop on form feed",
634 NULL
635 }
636 },
637 { OLETTER_NONE, &no_edit_warn_optname,
638 O_BOOL, OPT_OFF, &no_edit_warn, NULL,
639 {
640 "Warn when editing a file opened via LESSOPEN",
641 "Don't warn when editing a file opened via LESSOPEN",
642 NULL
643 }
644 },
645 { OLETTER_NONE, &nonum_headers_optname,
646 O_BOOL|O_REPAINT, 0, &nonum_headers, NULL,
647 {
648 "Number header lines",
649 "Don't number header lines",
650 NULL
651 }
652 },
653 { OLETTER_NONE, &nosearch_headers_optname,
654 O_BOOL|O_HL_REPAINT, 0, NULL, opt_nosearch_headers,
655 {
656 NULL, NULL, NULL
657 }
658 },
659 { OLETTER_NONE, &nosearch_header_lines_optname,
660 O_BOOL|O_HL_REPAINT, 0, NULL, opt_nosearch_header_lines,
661 {
662 NULL, NULL, NULL
663 }
664 },
665 { OLETTER_NONE, &nosearch_header_cols_optname,
666 O_BOOL|O_HL_REPAINT, 0, NULL, opt_nosearch_header_cols,
667 {
668 NULL, NULL, NULL
669 }
670 },
671 { OLETTER_NONE, &redraw_on_quit_optname,
672 O_BOOL, OPT_OFF, &redraw_on_quit, NULL,
673 {
674 "Don't redraw screen when quitting",
675 "Redraw last screen when quitting",
676 NULL
677 }
678 },
679 { OLETTER_NONE, &search_type_optname,
680 O_STRING, 0, NULL, opt_search_type,
681 { "Search options: ", "s", NULL }
682 },
683 { OLETTER_NONE, &exit_F_on_close_optname,
684 O_BOOL, OPT_OFF, &exit_F_on_close, NULL,
685 {
686 "Don't exit F command when input closes",
687 "Exit F command when input closes",
688 NULL
689 }
690 },
691 { OLETTER_NONE, &no_vbell_optname,
692 O_BOOL, OPT_OFF, &no_vbell, NULL,
693 {
694 "Display visual bell",
695 "Don't display visual bell",
696 NULL
697 }
698 },
699 { OLETTER_NONE, &modelines_optname,
700 O_NUMBER, 0, &modelines, NULL,
701 {
702 "Lines to read looking for modelines: ",
703 "Read %d lines looking for modelines",
704 NULL
705 }
706 },
707 { OLETTER_NONE, &intr_optname,
708 O_STRING, 0, NULL, opt_intr,
709 { "interrupt character: ", "s", NULL }
710 },
711 { OLETTER_NONE, &wordwrap_optname,
712 O_BOOL|O_REPAINT, OPT_OFF, &wordwrap, NULL,
713 {
714 "Wrap lines at any character",
715 "Wrap lines at spaces",
716 NULL
717 }
718 },
719 { OLETTER_NONE, &show_preproc_error_optname,
720 O_BOOL, OPT_OFF, &show_preproc_error, NULL,
721 {
722 "Don't show error message if preprocessor fails",
723 "Show error message if preprocessor fails",
724 NULL
725 }
726 },
727 { OLETTER_NONE, &proc_backspace_optname,
728 O_TRIPLE|O_REPAINT|O_HL_REPAINT, OPT_OFF, &proc_backspace, NULL,
729 {
730 "Backspace handling is specified by the -U option",
731 "Display underline text in underline mode",
732 "Print backspaces as ^H"
733 }
734 },
735 { OLETTER_NONE, &proc_tab_optname,
736 O_TRIPLE|O_REPAINT|O_HL_REPAINT, OPT_OFF, &proc_tab, NULL,
737 {
738 "Tab handling is specified by the -U option",
739 "Expand tabs to spaces",
740 "Print tabs as ^I"
741 }
742 },
743 { OLETTER_NONE, &proc_return_optname,
744 O_TRIPLE|O_REPAINT|O_HL_REPAINT, OPT_OFF, &proc_return, NULL,
745 {
746 "Carriage return handling is specified by the -U option",
747 "Delete carriage return before newline",
748 "Print carriage return as ^M"
749 }
750 },
751 { OLETTER_NONE, &match_shift_optname,
752 O_STRING|O_INIT_HANDLER, 0, NULL, opt_match_shift,
753 {
754 "Search match shift: ",
755 ".d",
756 NULL
757 }
758 },
759 #if LESSTEST
760 { OLETTER_NONE, &ttyin_name_optname,
761 O_STRING|O_NO_TOGGLE, 0, NULL, opt_ttyin_name,
762 {
763 NULL,
764 NULL,
765 NULL
766 }
767 },
768 #endif /*LESSTEST*/
769 { '\0', NULL, O_NOVAR, 0, NULL, NULL, { NULL, NULL, NULL } }
770 };
771
772
773 /*
774 * Initialize each option to its default value.
775 */
init_option(void)776 public void init_option(void)
777 {
778 struct loption *o;
779 constant char *p;
780
781 p = lgetenv("LESS_IS_MORE");
782 if (!isnullenv(p) && !(p[0] == '0' && p[1] == '\0'))
783 less_is_more = 1;
784
785 for (o = option; o->oletter != '\0'; o++)
786 {
787 /*
788 * Set each variable to its default.
789 */
790 if (o->ovar != NULL)
791 *(o->ovar) = o->odefault;
792 if (o->otype & O_INIT_HANDLER)
793 (*(o->ofunc))(INIT, (char *) NULL);
794 }
795 }
796
797 /*
798 * Find an option in the option table, given its option letter.
799 */
findopt(int c)800 public struct loption * findopt(int c)
801 {
802 struct loption *o;
803
804 for (o = option; o->oletter != '\0'; o++)
805 {
806 if (o->oletter == c)
807 return (o);
808 if ((o->otype & O_TRIPLE) && ASCII_TO_UPPER(o->oletter) == c)
809 return (o);
810 }
811 return (NULL);
812 }
813
814 /*
815 *
816 */
is_optchar(char c)817 static lbool is_optchar(char c)
818 {
819 if (ASCII_IS_UPPER(c))
820 return TRUE;
821 if (ASCII_IS_LOWER(c))
822 return TRUE;
823 if (c == '-')
824 return TRUE;
825 return FALSE;
826 }
827
828 /*
829 * Find an option in the option table, given its option name.
830 * p_optname is the (possibly partial) name to look for, and
831 * is updated to point after the matched name.
832 * p_oname if non-NULL is set to point to the full option name.
833 */
findopt_name(constant char ** p_optname,constant char ** p_oname,lbool * p_ambig)834 public struct loption * findopt_name(constant char **p_optname, constant char **p_oname, lbool *p_ambig)
835 {
836 constant char *optname = *p_optname;
837 struct loption *o;
838 struct optname *oname;
839 size_t len;
840 int uppercase;
841 struct loption *maxo = NULL;
842 struct optname *maxoname = NULL;
843 size_t maxlen = 0;
844 lbool ambig = FALSE;
845 lbool exact = FALSE;
846
847 /*
848 * Check all options.
849 */
850 for (o = option; o->oletter != '\0'; o++)
851 {
852 /*
853 * Check all names for this option.
854 */
855 for (oname = o->onames; oname != NULL; oname = oname->onext)
856 {
857 /*
858 * Try normal match first (uppercase == 0),
859 * then, then if it's a TRIPLE option,
860 * try uppercase match (uppercase == 1).
861 */
862 for (uppercase = 0; uppercase <= 1; uppercase++)
863 {
864 len = sprefix(optname, oname->oname, uppercase);
865 if (len == 0 || is_optchar(optname[len]))
866 {
867 /*
868 * We didn't use all of the option name.
869 */
870 continue;
871 }
872 if (!exact && len == maxlen)
873 /*
874 * Already had a partial match,
875 * and now there's another one that
876 * matches the same length.
877 */
878 ambig = TRUE;
879 else if (len > maxlen)
880 {
881 /*
882 * Found a better match than
883 * the one we had.
884 */
885 maxo = o;
886 maxoname = oname;
887 maxlen = len;
888 ambig = FALSE;
889 exact = (len == strlen(oname->oname));
890 }
891 if (!(o->otype & O_TRIPLE))
892 break;
893 }
894 }
895 }
896 if (p_ambig != NULL)
897 *p_ambig = ambig;
898 if (ambig)
899 {
900 /*
901 * Name matched more than one option.
902 */
903 return (NULL);
904 }
905 *p_optname = optname + maxlen;
906 if (p_oname != NULL)
907 *p_oname = maxoname == NULL ? NULL : maxoname->oname;
908 return (maxo);
909 }
910
911 /*
912 * Find all toggleable options whose names begin with a specified string.
913 * Return them in a space-separated string.
914 */
findopts_name(constant char * pfx)915 public char * findopts_name(constant char *pfx)
916 {
917 constant struct loption *o;
918 constant struct optname *oname;
919 struct xbuffer xbuf;
920 int uppercase;
921
922 xbuf_init(&xbuf);
923 for (o = option; o->oletter != '\0'; o++)
924 {
925 if (o->otype & O_NO_TOGGLE)
926 continue;
927 for (oname = o->onames; oname != NULL; oname = oname->onext)
928 {
929 for (uppercase = 0; uppercase <= 1; uppercase++)
930 {
931 size_t len = sprefix(pfx, oname->oname, uppercase);
932 if (len >= strlen(pfx))
933 {
934 constant char *np;
935 for (np = oname->oname; *np != '\0'; np++)
936 xbuf_add_char(&xbuf, uppercase && ASCII_IS_LOWER(*np) ? ASCII_TO_UPPER(*np) : *np);
937 xbuf_add_char(&xbuf, ' ');
938 }
939 if (!(o->otype & O_TRIPLE))
940 break;
941 }
942 }
943 }
944 xbuf_pop(&xbuf); /* remove final space */
945 xbuf_add_char(&xbuf, '\0');
946 return (char *) xbuf.data;
947 }
948