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