1 |
|
|
/* |
2 |
|
|
* Copyright (C) 1984-2012 Mark Nudelman |
3 |
|
|
* Modified for use with illumos by Garrett D'Amore. |
4 |
|
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
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 |
|
|
* The option table. |
14 |
|
|
*/ |
15 |
|
|
|
16 |
|
|
#include "less.h" |
17 |
|
|
#include "option.h" |
18 |
|
|
|
19 |
|
|
/* |
20 |
|
|
* Variables controlled by command line options. |
21 |
|
|
*/ |
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? */ |
54 |
|
|
|
55 |
|
|
int less_is_more = 0; /* Make compatible with POSIX more */ |
56 |
|
|
|
57 |
|
|
/* |
58 |
|
|
* Long option names. |
59 |
|
|
*/ |
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 }; |
104 |
|
|
|
105 |
|
|
|
106 |
|
|
/* |
107 |
|
|
* Table of all options and their semantics. |
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 |
112 |
|
|
* a new value, and odesc[1] is the description, which should contain |
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. |
117 |
|
|
*/ |
118 |
|
|
static struct loption option[] = { |
119 |
|
|
{ 'a', &a_optname, |
120 |
|
|
TRIPLE, OPT_ONPLUS, &how_search, NULL, |
121 |
|
|
{ |
122 |
|
|
"Search includes displayed screen", |
123 |
|
|
"Search skips displayed screen", |
124 |
|
|
"Search includes all of displayed screen" |
125 |
|
|
} |
126 |
|
|
}, |
127 |
|
|
|
128 |
|
|
{ 'b', &b_optname, |
129 |
|
|
NUMBER|INIT_HANDLER, 64, &bufspace, opt_b, |
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, |
145 |
|
|
TRIPLE|MORE_OK, OPT_ON, &top_scroll, NULL, |
146 |
|
|
{ |
147 |
|
|
"Repaint by scrolling from bottom of screen", |
148 |
|
|
"Repaint by painting from top of screen", |
149 |
|
|
"Repaint by painting from top of screen" |
150 |
|
|
} |
151 |
|
|
}, |
152 |
|
|
{ 'd', &d_optname, |
153 |
|
|
BOOL|MORE_OK|NO_TOGGLE, OPT_OFF, &know_dumb, NULL, |
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 |
|
|
} |
183 |
|
|
}, |
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", |
197 |
|
|
NULL |
198 |
|
|
} |
199 |
|
|
}, |
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, |
209 |
|
|
STRING, 0, NULL, opt_j, |
210 |
|
|
{ |
211 |
|
|
"Target line: ", |
212 |
|
|
"0123456789.-", |
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 |
|
|
} |
223 |
|
|
}, |
224 |
|
|
{ 'k', &k_optname, |
225 |
|
|
STRING|NO_TOGGLE|NO_QUERY, 0, NULL, opt_k, |
226 |
|
|
{ NULL, NULL, NULL } |
227 |
|
|
}, |
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 |
|
|
} |
235 |
|
|
}, |
236 |
|
|
{ 'L', &L__optname, |
237 |
|
|
BOOL, OPT_ON, &use_lessopen, NULL, |
238 |
|
|
{ |
239 |
|
|
"Don't use the LESSOPEN filter", |
240 |
|
|
"Use the LESSOPEN filter", |
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 |
|
|
} |
259 |
|
|
}, |
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 } |
267 |
|
|
}, |
268 |
|
|
{ 'p', &p_optname, |
269 |
|
|
STRING|NO_TOGGLE|NO_QUERY|MORE_OK, 0, NULL, opt_p, |
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", |
289 |
|
|
"Display control characters directly, " |
290 |
|
|
"processing ANSI sequences" |
291 |
|
|
} |
292 |
|
|
}, |
293 |
|
|
{ 's', &s_optname, |
294 |
|
|
BOOL|REPAINT|MORE_OK, OPT_OFF, &squeeze, NULL, |
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 |
|
|
} |
308 |
|
|
}, |
309 |
|
|
{ 't', &t_optname, |
310 |
|
|
STRING|NO_QUERY|MORE_OK, 0, NULL, opt_t, |
311 |
|
|
{ "tag: ", NULL, NULL } |
312 |
|
|
}, |
313 |
|
|
{ 'T', &T__optname, |
314 |
|
|
STRING|MORE_OK, 0, NULL, opt__T, |
315 |
|
|
{ "tags file: ", NULL, NULL } |
316 |
|
|
}, |
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", |
334 |
|
|
"Highlight first unread line after any " |
335 |
|
|
"forward movement", |
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, |
387 |
|
|
STRING, 0, NULL, opt_shift, |
388 |
|
|
{ |
389 |
|
|
"Horizontal shift: ", |
390 |
|
|
"0123456789.", |
391 |
|
|
NULL |
392 |
|
|
} |
393 |
|
|
}, |
394 |
|
|
{ OLETTER_NONE, &keypad_optname, |
395 |
|
|
BOOL|NO_TOGGLE, OPT_OFF, &no_keypad, NULL, |
396 |
|
|
{ |
397 |
|
|
"Use keypad mode", |
398 |
|
|
"Don't use keypad mode", |
399 |
|
|
NULL |
400 |
|
|
} |
401 |
|
|
}, |
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", |
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", |
422 |
|
|
"Don't use backslash escaping in command line " |
423 |
|
|
"parameters", |
424 |
|
|
NULL |
425 |
|
|
} |
426 |
|
|
}, |
427 |
|
|
{ '\0', NULL, NOVAR, 0, NULL, NULL, { NULL, NULL, NULL } } |
428 |
|
|
}; |
429 |
|
|
|
430 |
|
|
|
431 |
|
|
/* |
432 |
|
|
* Initialize each option to its default value. |
433 |
|
|
*/ |
434 |
|
|
void |
435 |
|
|
init_option(void) |
436 |
|
|
{ |
437 |
|
|
struct loption *o; |
438 |
|
|
|
439 |
✓✓ |
3471 |
for (o = option; o->oletter != '\0'; o++) { |
440 |
|
|
/* |
441 |
|
|
* Set each variable to its default. |
442 |
|
|
*/ |
443 |
✓✓ |
1677 |
if (o->ovar != NULL) |
444 |
|
1170 |
*(o->ovar) = o->odefault; |
445 |
✓✓ |
1677 |
if (o->otype & INIT_HANDLER) |
446 |
|
39 |
(*(o->ofunc))(INIT, NULL); |
447 |
|
|
} |
448 |
|
39 |
} |
449 |
|
|
|
450 |
|
|
/* |
451 |
|
|
* Find an option in the option table, given its option letter. |
452 |
|
|
*/ |
453 |
|
|
struct loption * |
454 |
|
|
findopt(int c) |
455 |
|
|
{ |
456 |
|
|
struct loption *o; |
457 |
|
|
|
458 |
✓✗ |
579 |
for (o = option; o->oletter != '\0'; o++) { |
459 |
✓✓ |
284 |
if (o->oletter == c) |
460 |
|
11 |
return (o); |
461 |
✓✓✗✓
|
370 |
if ((o->otype & TRIPLE) && |
462 |
|
97 |
(toupper((unsigned char)o->oletter) == c)) |
463 |
|
|
return (o); |
464 |
|
|
} |
465 |
|
|
return (NULL); |
466 |
|
11 |
} |
467 |
|
|
|
468 |
|
|
/* |
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 |
|
|
/* |
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 |
|
|
*/ |
486 |
|
|
struct loption * |
487 |
|
|
findopt_name(char **p_optname, char **p_oname, int *p_err) |
488 |
|
|
{ |
489 |
|
|
char *optname = *p_optname; |
490 |
|
|
struct loption *o; |
491 |
|
|
struct optname *oname; |
492 |
|
|
int len; |
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 |
|
|
*/ |
503 |
|
|
for (o = option; o->oletter != '\0'; o++) { |
504 |
|
|
/* |
505 |
|
|
* Check all names for this option. |
506 |
|
|
*/ |
507 |
|
|
for (oname = o->onames; oname != NULL; oname = oname->onext) { |
508 |
|
|
/* |
509 |
|
|
* Try normal match first (uppercase == 0), |
510 |
|
|
* then, then if it's a TRIPLE option, |
511 |
|
|
* try uppercase match (uppercase == 1). |
512 |
|
|
*/ |
513 |
|
|
for (uppercase = 0; uppercase <= 1; uppercase++) { |
514 |
|
|
len = sprefix(optname, oname->oname, uppercase); |
515 |
|
|
if (len <= 0 || is_optchar(optname[len])) { |
516 |
|
|
/* |
517 |
|
|
* We didn't use all of the option name. |
518 |
|
|
*/ |
519 |
|
|
continue; |
520 |
|
|
} |
521 |
|
|
if (!exact && len == maxlen) { |
522 |
|
|
/* |
523 |
|
|
* Already had a partial match, |
524 |
|
|
* and now there's another one that |
525 |
|
|
* matches the same length. |
526 |
|
|
*/ |
527 |
|
|
ambig = 1; |
528 |
|
|
} else if (len > maxlen) { |
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; |
537 |
|
|
exact = (len == strlen(oname->oname)); |
538 |
|
|
} |
539 |
|
|
if (!(o->otype & TRIPLE)) |
540 |
|
|
break; |
541 |
|
|
} |
542 |
|
|
} |
543 |
|
|
} |
544 |
|
|
if (ambig) { |
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); |
556 |
|
|
} |