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