Home | History | Annotate | Line # | Download | only in dist
      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  */
    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  */
    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  */
    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  */
    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