Annotation of src/usr.bin/less/opttbl.c, Revision 1.20
1.1 etheisen 1: /*
1.12 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.15 nicm 3: * Modified for use with illumos by Garrett D'Amore.
4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1 etheisen 5: *
1.6 millert 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.
1.1 etheisen 8: *
1.12 shadchin 9: * For more information, see the README file.
1.14 nicm 10: */
1.1 etheisen 11:
12: /*
13: * The option table.
14: */
15:
16: #include "less.h"
17: #include "option.h"
18:
19: /*
20: * Variables controlled by command line options.
21: */
1.14 nicm 22: int quiet; /* Should we suppress the audible bell? */
23: int how_search; /* Where should forward searches start? */
24: int top_scroll; /* Repaint screen from top? (vs scroll from bottom) */
25: int pr_type; /* Type of prompt (short, medium, long) */
26: int bs_mode; /* How to process backspaces */
27: int know_dumb; /* Don't complain about dumb terminals */
28: int quit_at_eof; /* Quit after hitting end of file twice */
29: int quit_if_one_screen; /* Quit if EOF on first screen */
30: int squeeze; /* Squeeze multiple blank lines into one */
31: int back_scroll; /* Repaint screen on backwards movement */
32: int forw_scroll; /* Repaint screen on forward movement */
33: int caseless; /* Do "caseless" searches */
34: int linenums; /* Use line numbers */
35: int autobuf; /* Automatically allocate buffers as needed */
36: int bufspace; /* Max buffer space per file (K) */
37: int ctldisp; /* Send control chars to screen untranslated */
38: int force_open; /* Open the file even if not regular file */
39: int swindow; /* Size of scrolling window */
40: int jump_sline; /* Screen line of "jump target" */
41: long jump_sline_fraction = -1;
42: int chopline; /* Truncate displayed lines at screen width */
43: int no_init; /* Disable sending ti/te termcap strings */
44: int no_keypad; /* Disable sending ks/ke termcap strings */
45: int twiddle; /* Show tildes after EOF */
46: int show_attn; /* Hilite first unread line */
47: int status_col; /* Display a status column */
48: int use_lessopen; /* Use the LESSOPEN filter */
49: int quit_on_intr; /* Quit on interrupt */
50: int follow_mode; /* F cmd Follows file desc or file name? */
51: int oldbot; /* Old bottom of screen behavior {{REMOVE}} */
52: int opt_use_backslash; /* Use backslash escaping in option parsing */
53: int hilite_search; /* Highlight matched search patterns? */
1.1 etheisen 54:
1.14 nicm 55: int less_is_more = 0; /* Make compatible with POSIX more */
1.10 shadchin 56:
1.1 etheisen 57: /*
1.6 millert 58: * Long option names.
59: */
1.14 nicm 60: static struct optname a_optname = { "search-skip-screen", NULL };
61: static struct optname b_optname = { "buffers", NULL };
62: static struct optname B__optname = { "auto-buffers", NULL };
63: static struct optname c_optname = { "clear-screen", NULL };
64: static struct optname d_optname = { "dumb", NULL };
65: static struct optname e_optname = { "quit-at-eof", NULL };
66: static struct optname f_optname = { "force", NULL };
67: static struct optname F__optname = { "quit-if-one-screen", NULL };
68: static struct optname g_optname = { "hilite-search", NULL };
69: static struct optname h_optname = { "max-back-scroll", NULL };
70: static struct optname i_optname = { "ignore-case", NULL };
71: static struct optname j_optname = { "jump-target", NULL };
72: static struct optname J__optname = { "status-column", NULL };
73: static struct optname k_optname = { "lesskey-file", NULL };
74: static struct optname K__optname = { "quit-on-intr", NULL };
75: static struct optname L__optname = { "no-lessopen", NULL };
76: static struct optname m_optname = { "long-prompt", NULL };
77: static struct optname n_optname = { "line-numbers", NULL };
78: static struct optname o_optname = { "log-file", NULL };
79: static struct optname O__optname = { "LOG-FILE", NULL };
80: static struct optname p_optname = { "pattern", NULL };
81: static struct optname P__optname = { "prompt", NULL };
82: static struct optname q2_optname = { "silent", NULL };
83: static struct optname q_optname = { "quiet", &q2_optname };
84: static struct optname r_optname = { "raw-control-chars", NULL };
85: static struct optname s_optname = { "squeeze-blank-lines", NULL };
86: static struct optname S__optname = { "chop-long-lines", NULL };
87: static struct optname t_optname = { "tag", NULL };
88: static struct optname T__optname = { "tag-file", NULL };
89: static struct optname u_optname = { "underline-special", NULL };
90: static struct optname V__optname = { "version", NULL };
91: static struct optname w_optname = { "hilite-unread", NULL };
92: static struct optname x_optname = { "tabs", NULL };
93: static struct optname X__optname = { "no-init", NULL };
94: static struct optname y_optname = { "max-forw-scroll", NULL };
95: static struct optname z_optname = { "window", NULL };
96: static struct optname quote_optname = { "quotes", NULL };
97: static struct optname tilde_optname = { "tilde", NULL };
98: static struct optname query_optname = { "help", NULL };
99: static struct optname pound_optname = { "shift", NULL };
100: static struct optname keypad_optname = { "no-keypad", NULL };
101: static struct optname oldbot_optname = { "old-bot", NULL };
102: static struct optname follow_optname = { "follow-name", NULL };
103: static struct optname use_backslash_optname = { "use-backslash", NULL };
1.6 millert 104:
105:
106: /*
1.1 etheisen 107: * Table of all options and their semantics.
1.6 millert 108: *
109: * For BOOL and TRIPLE options, odesc[0], odesc[1], odesc[2] are
110: * the description of the option when set to 0, 1 or 2, respectively.
111: * For NUMBER options, odesc[0] is the prompt to use when entering
1.14 nicm 112: * a new value, and odesc[1] is the description, which should contain
1.6 millert 113: * one %d which is replaced by the value of the number.
114: * For STRING options, odesc[0] is the prompt to use when entering
115: * a new value, and odesc[1], if not NULL, is the set of characters
116: * that are valid in the string.
1.1 etheisen 117: */
1.14 nicm 118: static struct loption option[] = {
1.6 millert 119: { 'a', &a_optname,
1.10 shadchin 120: TRIPLE, OPT_ONPLUS, &how_search, NULL,
1.6 millert 121: {
122: "Search includes displayed screen",
123: "Search skips displayed screen",
1.10 shadchin 124: "Search includes all of displayed screen"
1.6 millert 125: }
126: },
127:
128: { 'b', &b_optname,
1.14 nicm 129: NUMBER|INIT_HANDLER, 64, &bufspace, opt_b,
1.6 millert 130: {
131: "Max buffer space per file (K): ",
132: "Max buffer space per file: %dK",
133: NULL
134: }
135: },
136: { 'B', &B__optname,
137: BOOL, OPT_ON, &autobuf, NULL,
138: {
139: "Don't automatically allocate buffers",
140: "Automatically allocate buffers when needed",
141: NULL
142: }
143: },
144: { 'c', &c_optname,
1.14 nicm 145: TRIPLE|MORE_OK, OPT_ON, &top_scroll, NULL,
1.6 millert 146: {
147: "Repaint by scrolling from bottom of screen",
1.10 shadchin 148: "Repaint by painting from top of screen",
1.6 millert 149: "Repaint by painting from top of screen"
150: }
151: },
152: { 'd', &d_optname,
1.14 nicm 153: BOOL|MORE_OK|NO_TOGGLE, OPT_OFF, &know_dumb, NULL,
1.6 millert 154: {
155: "Assume intelligent terminal",
156: "Assume dumb terminal",
157: NULL
158: }
159: },
160: { 'e', &e_optname,
161: TRIPLE, OPT_OFF, &quit_at_eof, NULL,
162: {
163: "Don't quit at end-of-file",
164: "Quit at end-of-file",
165: "Quit immediately at end-of-file"
166: }
167: },
168: { 'f', &f_optname,
169: BOOL, OPT_OFF, &force_open, NULL,
170: {
171: "Open only regular files",
172: "Open even non-regular files",
173: NULL
174: }
175: },
176: { 'F', &F__optname,
177: BOOL, OPT_OFF, &quit_if_one_screen, NULL,
178: {
179: "Don't quit if end-of-file on first screen",
180: "Quit if end-of-file on first screen",
181: NULL
182: }
1.1 etheisen 183: },
1.6 millert 184: { 'g', &g_optname,
185: TRIPLE|HL_REPAINT, OPT_ONPLUS, &hilite_search, NULL,
186: {
187: "Don't highlight search matches",
188: "Highlight matches for previous search only",
189: "Highlight all matches for previous search pattern",
190: }
191: },
192: { 'h', &h_optname,
193: NUMBER, -1, &back_scroll, NULL,
194: {
195: "Backwards scroll limit: ",
196: "Backwards scroll limit is %d lines",
1.7 millert 197: NULL
198: }
199: },
1.6 millert 200: { 'i', &i_optname,
201: TRIPLE|HL_REPAINT, OPT_OFF, &caseless, opt_i,
202: {
203: "Case is significant in searches",
204: "Ignore case in searches",
205: "Ignore case in searches and in patterns"
206: }
207: },
208: { 'j', &j_optname,
1.10 shadchin 209: STRING, 0, NULL, opt_j,
1.6 millert 210: {
211: "Target line: ",
1.10 shadchin 212: "0123456789.-",
1.6 millert 213: NULL
214: }
215: },
216: { 'J', &J__optname,
217: BOOL|REPAINT, OPT_OFF, &status_col, NULL,
218: {
219: "Don't display a status column",
220: "Display a status column",
221: NULL
222: }
1.1 etheisen 223: },
1.6 millert 224: { 'k', &k_optname,
225: STRING|NO_TOGGLE|NO_QUERY, 0, NULL, opt_k,
226: { NULL, NULL, NULL }
1.1 etheisen 227: },
1.10 shadchin 228: { 'K', &K__optname,
229: BOOL, OPT_OFF, &quit_on_intr, NULL,
230: {
231: "Interrupt (ctrl-C) returns to prompt",
232: "Interrupt (ctrl-C) exits less",
233: NULL
234: }
1.6 millert 235: },
236: { 'L', &L__optname,
237: BOOL, OPT_ON, &use_lessopen, NULL,
238: {
1.20 ! guenther 239: "(ignored)",
! 240: "(ignored)",
1.6 millert 241: NULL
242: }
243: },
244: { 'm', &m_optname,
245: TRIPLE, OPT_OFF, &pr_type, NULL,
246: {
247: "Short prompt",
248: "Medium prompt",
249: "Long prompt"
250: }
251: },
252: { 'n', &n_optname,
253: TRIPLE|REPAINT, OPT_ON, &linenums, NULL,
254: {
255: "Don't use line numbers",
256: "Use line numbers",
257: "Constantly display line numbers"
258: }
1.1 etheisen 259: },
1.6 millert 260: { 'o', &o_optname,
261: STRING, 0, NULL, opt_o,
262: { "log file: ", NULL, NULL }
263: },
264: { 'O', &O__optname,
265: STRING, 0, NULL, opt__O,
266: { "Log file: ", NULL, NULL }
1.1 etheisen 267: },
1.6 millert 268: { 'p', &p_optname,
1.14 nicm 269: STRING|NO_TOGGLE|NO_QUERY|MORE_OK, 0, NULL, opt_p,
1.6 millert 270: { NULL, NULL, NULL }
271: },
272: { 'P', &P__optname,
273: STRING, 0, NULL, opt__P,
274: { "prompt: ", NULL, NULL }
275: },
276: { 'q', &q_optname,
277: TRIPLE, OPT_OFF, &quiet, NULL,
278: {
279: "Ring the bell for errors AND at eof/bof",
280: "Ring the bell for errors but not at eof/bof",
281: "Never ring the bell"
282: }
283: },
284: { 'r', &r_optname,
285: TRIPLE|REPAINT, OPT_OFF, &ctldisp, NULL,
286: {
287: "Display control characters as ^X",
288: "Display control characters directly",
1.14 nicm 289: "Display control characters directly, "
290: "processing ANSI sequences"
1.6 millert 291: }
292: },
293: { 's', &s_optname,
1.14 nicm 294: BOOL|REPAINT|MORE_OK, OPT_OFF, &squeeze, NULL,
1.6 millert 295: {
296: "Display all blank lines",
297: "Squeeze multiple blank lines",
298: NULL
299: }
300: },
301: { 'S', &S__optname,
302: BOOL|REPAINT, OPT_OFF, &chopline, NULL,
303: {
304: "Fold long lines",
305: "Chop long lines",
306: NULL
307: }
1.1 etheisen 308: },
1.6 millert 309: { 't', &t_optname,
1.14 nicm 310: STRING|NO_QUERY|MORE_OK, 0, NULL, opt_t,
1.6 millert 311: { "tag: ", NULL, NULL }
312: },
313: { 'T', &T__optname,
1.14 nicm 314: STRING|MORE_OK, 0, NULL, opt__T,
1.6 millert 315: { "tags file: ", NULL, NULL }
1.1 etheisen 316: },
1.6 millert 317: { 'u', &u_optname,
318: TRIPLE|REPAINT, OPT_OFF, &bs_mode, NULL,
319: {
320: "Display underlined text in underline mode",
321: "Backspaces cause overstrike",
322: "Print backspace as ^H"
323: }
324: },
325: { 'V', &V__optname,
326: NOVAR, 0, NULL, opt__V,
327: { NULL, NULL, NULL }
328: },
329: { 'w', &w_optname,
330: TRIPLE|REPAINT, OPT_OFF, &show_attn, NULL,
331: {
332: "Don't highlight first unread line",
333: "Highlight first unread line after forward-screen",
1.14 nicm 334: "Highlight first unread line after any "
335: "forward movement",
1.6 millert 336: }
337: },
338: { 'x', &x_optname,
339: STRING|REPAINT, 0, NULL, opt_x,
340: {
341: "Tab stops: ",
342: "0123456789,",
343: NULL
344: }
345: },
346: { 'X', &X__optname,
347: BOOL|NO_TOGGLE, OPT_OFF, &no_init, NULL,
348: {
349: "Send init/deinit strings to terminal",
350: "Don't use init/deinit strings",
351: NULL
352: }
353: },
354: { 'y', &y_optname,
355: NUMBER, -1, &forw_scroll, NULL,
356: {
357: "Forward scroll limit: ",
358: "Forward scroll limit is %d lines",
359: NULL
360: }
361: },
362: { 'z', &z_optname,
363: NUMBER, -1, &swindow, NULL,
364: {
365: "Scroll window size: ",
366: "Scroll window size is %d lines",
367: NULL
368: }
369: },
370: { '"', "e_optname,
371: STRING, 0, NULL, opt_quote,
372: { "quotes: ", NULL, NULL }
373: },
374: { '~', &tilde_optname,
375: BOOL|REPAINT, OPT_ON, &twiddle, NULL,
376: {
377: "Don't show tildes after end of file",
378: "Show tildes after end of file",
379: NULL
380: }
381: },
382: { '?', &query_optname,
383: NOVAR, 0, NULL, opt_query,
384: { NULL, NULL, NULL }
385: },
386: { '#', £_optname,
1.10 shadchin 387: STRING, 0, NULL, opt_shift,
1.6 millert 388: {
389: "Horizontal shift: ",
1.10 shadchin 390: "0123456789.",
1.6 millert 391: NULL
392: }
393: },
1.10 shadchin 394: { OLETTER_NONE, &keypad_optname,
1.6 millert 395: BOOL|NO_TOGGLE, OPT_OFF, &no_keypad, NULL,
396: {
397: "Use keypad mode",
398: "Don't use keypad mode",
399: NULL
400: }
1.1 etheisen 401: },
1.10 shadchin 402: { OLETTER_NONE, &oldbot_optname,
403: BOOL, OPT_OFF, &oldbot, NULL,
404: {
405: "Use new bottom of screen behavior",
406: "Use old bottom of screen behavior",
407: NULL
408: }
409: },
410: { OLETTER_NONE, &follow_optname,
411: BOOL, FOLLOW_DESC, &follow_mode, NULL,
412: {
413: "F command follows file descriptor",
414: "F command follows file name",
1.12 shadchin 415: NULL
416: }
417: },
418: { OLETTER_NONE, &use_backslash_optname,
419: BOOL, OPT_OFF, &opt_use_backslash, NULL,
420: {
421: "Use backslash escaping in command line parameters",
1.14 nicm 422: "Don't use backslash escaping in command line "
423: "parameters",
1.10 shadchin 424: NULL
425: }
426: },
1.6 millert 427: { '\0', NULL, NOVAR, 0, NULL, NULL, { NULL, NULL, NULL } }
1.1 etheisen 428: };
429:
430:
431: /*
432: * Initialize each option to its default value.
433: */
1.14 nicm 434: void
435: init_option(void)
1.1 etheisen 436: {
1.14 nicm 437: struct loption *o;
1.10 shadchin 438:
1.19 deraadt 439: for (o = option; o->oletter != '\0'; o++) {
1.6 millert 440: /*
1.1 etheisen 441: * Set each variable to its default.
442: */
443: if (o->ovar != NULL)
444: *(o->ovar) = o->odefault;
1.6 millert 445: if (o->otype & INIT_HANDLER)
1.14 nicm 446: (*(o->ofunc))(INIT, NULL);
1.1 etheisen 447: }
448: }
449:
450: /*
1.6 millert 451: * Find an option in the option table, given its option letter.
1.1 etheisen 452: */
1.14 nicm 453: struct loption *
454: findopt(int c)
1.1 etheisen 455: {
1.14 nicm 456: struct loption *o;
1.1 etheisen 457:
1.19 deraadt 458: for (o = option; o->oletter != '\0'; o++) {
1.1 etheisen 459: if (o->oletter == c)
460: return (o);
1.16 mmcc 461: if ((o->otype & TRIPLE) &&
462: (toupper((unsigned char)o->oletter) == c))
1.1 etheisen 463: return (o);
464: }
465: return (NULL);
1.6 millert 466: }
467:
468: /*
1.18 mmcc 469: *
470: */
471: static int
472: is_optchar(unsigned char c)
473: {
474: if (isupper(c) || islower(c) || c == '-')
475: return (1);
476: else
477: return (0);
478: }
479:
480: /*
1.6 millert 481: * Find an option in the option table, given its option name.
482: * p_optname is the (possibly partial) name to look for, and
483: * is updated to point after the matched name.
484: * p_oname if non-NULL is set to point to the full option name.
485: */
1.14 nicm 486: struct loption *
487: findopt_name(char **p_optname, char **p_oname, int *p_err)
1.6 millert 488: {
489: char *optname = *p_optname;
1.14 nicm 490: struct loption *o;
491: struct optname *oname;
492: int len;
1.6 millert 493: int uppercase;
494: struct loption *maxo = NULL;
495: struct optname *maxoname = NULL;
496: int maxlen = 0;
497: int ambig = 0;
498: int exact = 0;
499:
500: /*
501: * Check all options.
502: */
1.19 deraadt 503: for (o = option; o->oletter != '\0'; o++) {
1.6 millert 504: /*
505: * Check all names for this option.
506: */
1.19 deraadt 507: for (oname = o->onames; oname != NULL; oname = oname->onext) {
1.14 nicm 508: /*
1.6 millert 509: * Try normal match first (uppercase == 0),
510: * then, then if it's a TRIPLE option,
511: * try uppercase match (uppercase == 1).
512: */
1.19 deraadt 513: for (uppercase = 0; uppercase <= 1; uppercase++) {
1.6 millert 514: len = sprefix(optname, oname->oname, uppercase);
1.18 mmcc 515: if (len <= 0 || is_optchar(optname[len])) {
1.6 millert 516: /*
517: * We didn't use all of the option name.
518: */
519: continue;
520: }
1.14 nicm 521: if (!exact && len == maxlen) {
1.6 millert 522: /*
523: * Already had a partial match,
524: * and now there's another one that
525: * matches the same length.
526: */
527: ambig = 1;
1.14 nicm 528: } else if (len > maxlen) {
1.6 millert 529: /*
530: * Found a better match than
531: * the one we had.
532: */
533: maxo = o;
534: maxoname = oname;
535: maxlen = len;
536: ambig = 0;
1.14 nicm 537: exact = (len == strlen(oname->oname));
1.6 millert 538: }
539: if (!(o->otype & TRIPLE))
540: break;
541: }
542: }
543: }
1.14 nicm 544: if (ambig) {
1.6 millert 545: /*
546: * Name matched more than one option.
547: */
548: if (p_err != NULL)
549: *p_err = OPT_AMBIG;
550: return (NULL);
551: }
552: *p_optname = optname + maxlen;
553: if (p_oname != NULL)
554: *p_oname = maxoname == NULL ? NULL : maxoname->oname;
555: return (maxo);
1.1 etheisen 556: }