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 */
23public int quiet;               /* Should we suppress the audible bell? */
24public int no_vbell;            /* Should we suppress the visual bell? */
25public int how_search;          /* Where should forward searches start? */
26public int top_scroll;          /* Repaint screen from top?
27                                   (alternative is scroll from bottom) */
28public int pr_type;             /* Type of prompt (short, medium, long) */
29public int bs_mode;             /* How to process backspaces */
30public int know_dumb;           /* Don't complain about dumb terminals */
31public int quit_at_eof;         /* Quit after hitting end of file twice */
32public int quit_if_one_screen;  /* Quit if EOF on first screen */
33public int be_helpful;          /* more(1) style -d */
34public int squeeze;             /* Squeeze multiple blank lines into one */
35public int tabstop;             /* Tab settings */
36public int back_scroll;         /* Repaint screen on backwards movement */
37public int forw_scroll;         /* Repaint screen on forward movement */
38public int caseless;            /* Do "caseless" searches */
39public int linenums;            /* Use line numbers */
40public int autobuf;             /* Automatically allocate buffers as needed */
41public int bufspace;            /* Max buffer space per file (K) */
42public int ctldisp;             /* Send control chars to screen untranslated */
43public int force_open;          /* Open the file even if not regular file */
44public int swindow;             /* Size of scrolling window */
45public int jump_sline;          /* Screen line of "jump target" */
46public long jump_sline_fraction = -1;
47public long shift_count_fraction = -1;
48public int chopline;            /* Truncate displayed lines at screen width */
49public int wordwrap;            /* Wrap lines at space */
50public int no_init;             /* Disable sending ti/te termcap strings */
51public int no_keypad;           /* Disable sending ks/ke termcap strings */
52public int twiddle;             /* Show tildes after EOF */
53public int show_attn;           /* Hilite first unread line */
54public int shift_count;         /* Number of positions to shift horizontally */
55public int status_col;          /* Display a status column */
56public int use_lessopen;        /* Use the LESSOPEN filter */
57public int quit_on_intr;        /* Quit on interrupt */
58public int follow_mode;         /* F cmd Follows file desc or file name? */
59public int oldbot;              /* Old bottom of screen behavior {{REMOVE}} */
60public int opt_use_backslash;   /* Use backslash escaping in option parsing */
61public char rscroll_char;       /* Char which marks chopped lines with -S */
62public int rscroll_attr;        /* Attribute of rscroll_char */
63public int no_hist_dups;        /* Remove dups from history list */
64public int mousecap;            /* Allow mouse for scrolling */
65public int wheel_lines;         /* Number of lines to scroll on mouse wheel scroll */
66public int perma_marks;         /* Save marks in history file */
67public int linenum_width;       /* Width of line numbers */
68public int status_col_width;    /* Width of status column */
69public int incr_search;         /* Incremental search */
70public int use_color;           /* Use UI color */
71public int want_filesize;       /* Scan to EOF if necessary to get file size */
72public int status_line;         /* Highlight entire marked lines */
73public int header_lines;        /* Freeze header lines at top of screen */
74public int header_cols;         /* Freeze header columns at left of screen */
75public int nonum_headers;       /* Don't give headers line numbers */
76public int nosearch_headers;    /* Don't search in header lines or columns */
77public int redraw_on_quit;      /* Redraw last screen after term deinit */
78public int def_search_type;     /* */
79public int exit_F_on_close;     /* Exit F command when input closes */
80public int modelines;           /* Lines to read looking for modelines */
81public int show_preproc_error;  /* Display msg when preproc exits with error */
82public int proc_backspace;      /* Special handling of backspace */
83public int proc_tab;            /* Special handling of tab */
84public int proc_return;         /* Special handling of carriage return */
85public char intr_char = CONTROL('X'); /* Char to interrupt reads */
86#if HILITE_SEARCH
87public int hilite_search;       /* Highlight matched search patterns? */
88#endif
89
90public int less_is_more = 0;    /* Make compatible with POSIX more */
91
92/*
93 * Long option names.
94 */
95static struct optname a_optname      = { "search-skip-screen",   NULL };
96static struct optname b_optname      = { "buffers",              NULL };
97static struct optname B__optname     = { "auto-buffers",         NULL };
98static struct optname c_optname      = { "clear-screen",         NULL };
99static struct optname d_optname      = { "dumb",                 NULL };
100static struct optname D__optname     = { "color",                NULL };
101static struct optname e_optname      = { "quit-at-eof",          NULL };
102static struct optname f_optname      = { "force",                NULL };
103static struct optname F__optname     = { "quit-if-one-screen",   NULL };
104#if HILITE_SEARCH
105static struct optname g_optname      = { "hilite-search",        NULL };
106#endif
107static struct optname h_optname      = { "max-back-scroll",      NULL };
108static struct optname i_optname      = { "ignore-case",          NULL };
109static struct optname j_optname      = { "jump-target",          NULL };
110static struct optname J__optname     = { "status-column",        NULL };
111#if USERFILE
112static struct optname k_optname      = { "lesskey-file",         NULL };
113#if HAVE_LESSKEYSRC
114static struct optname ks_optname     = { "lesskey-src",          NULL };
115#endif /* HAVE_LESSKEYSRC */
116#endif
117static struct optname K__optname     = { "quit-on-intr",         NULL };
118static struct optname L__optname     = { "no-lessopen",          NULL };
119static struct optname m_optname      = { "long-prompt",          NULL };
120static struct optname n_optname      = { "line-numbers",         NULL };
121#if LOGFILE
122static struct optname o_optname      = { "log-file",             NULL };
123static struct optname O__optname     = { "LOG-FILE",             NULL };
124#endif
125static struct optname p_optname      = { "pattern",              NULL };
126static struct optname P__optname     = { "prompt",               NULL };
127static struct optname q2_optname     = { "silent",               NULL };
128static struct optname q_optname      = { "quiet",                &q2_optname };
129static struct optname r_optname      = { "raw-control-chars",    NULL };
130static struct optname s_optname      = { "squeeze-blank-lines",  NULL };
131static struct optname S__optname     = { "chop-long-lines",      NULL };
132#if TAGS
133static struct optname t_optname      = { "tag",                  NULL };
134static struct optname T__optname     = { "tag-file",             NULL };
135#endif
136static struct optname u_optname      = { "underline-special",    NULL };
137static struct optname V__optname     = { "version",              NULL };
138static struct optname w_optname      = { "hilite-unread",        NULL };
139static struct optname x_optname      = { "tabs",                 NULL };
140static struct optname X__optname     = { "no-init",              NULL };
141static struct optname y_optname      = { "max-forw-scroll",      NULL };
142static struct optname z_optname      = { "window",               NULL };
143static struct optname quote_optname  = { "quotes",               NULL };
144static struct optname tilde_optname  = { "tilde",                NULL };
145static struct optname query_optname  = { "help",                 NULL };
146static struct optname pound_optname  = { "shift",                NULL };
147static struct optname keypad_optname = { "no-keypad",            NULL };
148static struct optname oldbot_optname = { "old-bot",              NULL };
149static struct optname follow_optname = { "follow-name",          NULL };
150static struct optname use_backslash_optname = { "use-backslash", NULL };
151static struct optname rscroll_optname = { "rscroll", NULL };
152static struct optname nohistdups_optname = { "no-histdups",      NULL };
153static struct optname mousecap_optname = { "mouse",              NULL };
154static struct optname wheel_lines_optname = { "wheel-lines",     NULL };
155static struct optname perma_marks_optname = { "save-marks",      NULL };
156static struct optname linenum_width_optname = { "line-num-width", NULL };
157static struct optname status_col_width_optname = { "status-col-width", NULL };
158static struct optname incr_search_optname = { "incsearch",       NULL };
159static struct optname use_color_optname = { "use-color",         NULL };
160static struct optname want_filesize_optname = { "file-size",     NULL };
161static struct optname status_line_optname = { "status-line",     NULL };
162static struct optname header_optname = { "header",               NULL };
163static struct optname nonum_headers_optname = { "no-number-headers", NULL };
164static struct optname nosearch_headers_optname = { "no-search-headers", NULL };
165static struct optname redraw_on_quit_optname = { "redraw-on-quit", NULL };
166static struct optname search_type_optname = { "search-options", NULL };
167static struct optname exit_F_on_close_optname = { "exit-follow-on-close", NULL };
168static struct optname modelines_optname = { "modelines", NULL };
169static struct optname no_vbell_optname = { "no-vbell", NULL };
170static struct optname intr_optname = { "intr", NULL };
171static struct optname wordwrap_optname = { "wordwrap", NULL };
172static struct optname show_preproc_error_optname = { "show-preproc-errors", NULL };
173static struct optname proc_backspace_optname = { "proc-backspace", NULL };
174static struct optname proc_tab_optname = { "proc-tab", NULL };
175static struct optname proc_return_optname = { "proc-return", NULL };
176#if LESSTEST
177static 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 */
193static 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 */
739public 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 */
763public 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 */
780static 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 */
797public 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