1a5f0fb15SPaul Saab /* 2*c77c4889SXin LI * Copyright (C) 1984-2024 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 796e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab /* 12a5f0fb15SPaul Saab * Process command line options. 13a5f0fb15SPaul Saab * 14a5f0fb15SPaul Saab * Each option is a single letter which controls a program variable. 15a5f0fb15SPaul Saab * The options have defaults which may be changed via 16a5f0fb15SPaul Saab * the command line option, toggled via the "-" command, 17a5f0fb15SPaul Saab * or queried via the "_" command. 18a5f0fb15SPaul Saab */ 19a5f0fb15SPaul Saab 20a5f0fb15SPaul Saab #include "less.h" 21a5f0fb15SPaul Saab #include "option.h" 22a5f0fb15SPaul Saab 23000ba3e8STim J. Robbins static struct loption *pendopt; 24*c77c4889SXin LI public lbool plusoption = FALSE; 25a5f0fb15SPaul Saab 26*c77c4889SXin LI static constant char *optstring(constant char *s, char **p_str, constant char *printopt, constant char *validchars); 27d713e089SXin LI static int flip_triple(int val, int lc); 28a5f0fb15SPaul Saab 297f074f9cSXin LI extern int less_is_more; 307f074f9cSXin LI extern int quit_at_eof; 31a5f0fb15SPaul Saab extern char *every_first_cmd; 327bd2567cSXin LI extern int opt_use_backslash; 33a5f0fb15SPaul Saab 34a5f0fb15SPaul Saab /* 3533096f16SXin LI * Return a printable description of an option. 3633096f16SXin LI */ 37*c77c4889SXin LI static constant char * opt_desc(struct loption *o) 3833096f16SXin LI { 3933096f16SXin LI static char buf[OPTNAME_MAX + 10]; 4033096f16SXin LI if (o->oletter == OLETTER_NONE) 4133096f16SXin LI SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname); 4233096f16SXin LI else 4333096f16SXin LI SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname); 4433096f16SXin LI return (buf); 4533096f16SXin LI } 4633096f16SXin LI 4733096f16SXin LI /* 4833096f16SXin LI * Return a string suitable for printing as the "name" of an option. 4933096f16SXin LI * For example, if the option letter is 'x', just return "-x". 5033096f16SXin LI */ 51*c77c4889SXin LI public constant char * propt(char c) 5233096f16SXin LI { 5395270f73SXin LI static char buf[MAX_PRCHAR_LEN+2]; 5433096f16SXin LI 55*c77c4889SXin LI sprintf(buf, "-%s", prchar((LWCHAR) c)); 5633096f16SXin LI return (buf); 5733096f16SXin LI } 5833096f16SXin LI 5933096f16SXin LI /* 60a5f0fb15SPaul Saab * Scan an argument (either from the command line or from the 61a5f0fb15SPaul Saab * LESS environment variable) and process it. 62a5f0fb15SPaul Saab */ 63*c77c4889SXin LI public void scan_option(constant char *s) 64a5f0fb15SPaul Saab { 651ea31627SRobert Watson struct loption *o; 66*c77c4889SXin LI char optc; 67*c77c4889SXin LI constant char *optname; 68*c77c4889SXin LI constant char *printopt; 69a5f0fb15SPaul Saab char *str; 70*c77c4889SXin LI lbool set_default; 71a5f0fb15SPaul Saab int lc; 72*c77c4889SXin LI lbool ambig; 73a5f0fb15SPaul Saab PARG parg; 74a5f0fb15SPaul Saab 75a5f0fb15SPaul Saab if (s == NULL) 76a5f0fb15SPaul Saab return; 77a5f0fb15SPaul Saab 78a5f0fb15SPaul Saab /* 79a5f0fb15SPaul Saab * If we have a pending option which requires an argument, 80a5f0fb15SPaul Saab * handle it now. 81a5f0fb15SPaul Saab * This happens if the previous option was, for example, "-P" 82a5f0fb15SPaul Saab * without a following string. In that case, the current 83a5f0fb15SPaul Saab * option is simply the argument for the previous option. 84a5f0fb15SPaul Saab */ 85a5f0fb15SPaul Saab if (pendopt != NULL) 86a5f0fb15SPaul Saab { 87*c77c4889SXin LI if (!(pendopt->otype & UNSUPPORTED)) 88*c77c4889SXin LI { 89a5f0fb15SPaul Saab switch (pendopt->otype & OTYPE) 90a5f0fb15SPaul Saab { 91a5f0fb15SPaul Saab case STRING: 92a5f0fb15SPaul Saab (*pendopt->ofunc)(INIT, s); 93a5f0fb15SPaul Saab break; 94a5f0fb15SPaul Saab case NUMBER: 9533096f16SXin LI printopt = opt_desc(pendopt); 96*c77c4889SXin LI *(pendopt->ovar) = getnumc(&s, printopt, NULL); 97a5f0fb15SPaul Saab break; 98a5f0fb15SPaul Saab } 99*c77c4889SXin LI } 100a5f0fb15SPaul Saab pendopt = NULL; 101a5f0fb15SPaul Saab return; 102a5f0fb15SPaul Saab } 103a5f0fb15SPaul Saab 104a5f0fb15SPaul Saab set_default = FALSE; 105a5f0fb15SPaul Saab optname = NULL; 106a5f0fb15SPaul Saab 107a5f0fb15SPaul Saab while (*s != '\0') 108a5f0fb15SPaul Saab { 109a5f0fb15SPaul Saab /* 110a5f0fb15SPaul Saab * Check some special cases first. 111a5f0fb15SPaul Saab */ 112a5f0fb15SPaul Saab switch (optc = *s++) 113a5f0fb15SPaul Saab { 114a5f0fb15SPaul Saab case ' ': 115a5f0fb15SPaul Saab case '\t': 116a5f0fb15SPaul Saab case END_OPTION_STRING: 117a5f0fb15SPaul Saab continue; 118a5f0fb15SPaul Saab case '-': 119a5f0fb15SPaul Saab /* 120a5f0fb15SPaul Saab * "--" indicates an option name instead of a letter. 121a5f0fb15SPaul Saab */ 122a5f0fb15SPaul Saab if (*s == '-') 123a5f0fb15SPaul Saab optname = ++s; 124a5f0fb15SPaul Saab /* 125*c77c4889SXin LI * "-+" or "--+" means set these options back to their defaults. 126*c77c4889SXin LI * (They may have been set otherwise by previous options.) 127a5f0fb15SPaul Saab */ 128a5f0fb15SPaul Saab set_default = (*s == '+'); 129a5f0fb15SPaul Saab if (set_default) 130a5f0fb15SPaul Saab s++; 131*c77c4889SXin LI if (optname != NULL) 132*c77c4889SXin LI { 133*c77c4889SXin LI optname = s; 134*c77c4889SXin LI break; 135*c77c4889SXin LI } 136a5f0fb15SPaul Saab continue; 137a5f0fb15SPaul Saab case '+': 138a5f0fb15SPaul Saab /* 139a5f0fb15SPaul Saab * An option prefixed by a "+" is ungotten, so 140a5f0fb15SPaul Saab * that it is interpreted as less commands 141a5f0fb15SPaul Saab * processed at the start of the first input file. 142a5f0fb15SPaul Saab * "++" means process the commands at the start of 143a5f0fb15SPaul Saab * EVERY input file. 144a5f0fb15SPaul Saab */ 145a5f0fb15SPaul Saab plusoption = TRUE; 146000ba3e8STim J. Robbins s = optstring(s, &str, propt('+'), NULL); 1474cc5fc9aSXin LI if (s == NULL) 1484cc5fc9aSXin LI return; 149c9346414SPaul Saab if (*str == '+') 150b7780dbeSXin LI { 151b7780dbeSXin LI if (every_first_cmd != NULL) 152b7780dbeSXin LI free(every_first_cmd); 15321fa6541SXin LI every_first_cmd = save(str+1); 154b7780dbeSXin LI } else 155a15691bfSXin LI { 156c9346414SPaul Saab ungetsc(str); 157*c77c4889SXin LI ungetcc_end_command(); 158a15691bfSXin LI } 1594cc5fc9aSXin LI free(str); 160a5f0fb15SPaul Saab continue; 161a5f0fb15SPaul Saab case '0': case '1': case '2': case '3': case '4': 162a5f0fb15SPaul Saab case '5': case '6': case '7': case '8': case '9': 163a5f0fb15SPaul Saab /* 164a5f0fb15SPaul Saab * Special "more" compatibility form "-<number>" 165a5f0fb15SPaul Saab * instead of -z<number> to set the scrolling 166a5f0fb15SPaul Saab * window size. 167a5f0fb15SPaul Saab */ 168a5f0fb15SPaul Saab s--; 169a5f0fb15SPaul Saab optc = 'z'; 170a5f0fb15SPaul Saab break; 1717f074f9cSXin LI case 'n': 1727f074f9cSXin LI if (less_is_more) 1737f074f9cSXin LI optc = 'z'; 1747f074f9cSXin LI break; 175a5f0fb15SPaul Saab } 176a5f0fb15SPaul Saab 177a5f0fb15SPaul Saab /* 178a5f0fb15SPaul Saab * Not a special case. 179a5f0fb15SPaul Saab * Look up the option letter in the option table. 180a5f0fb15SPaul Saab */ 181*c77c4889SXin LI ambig = FALSE; 182a5f0fb15SPaul Saab if (optname == NULL) 183a5f0fb15SPaul Saab { 184a5f0fb15SPaul Saab printopt = propt(optc); 1856dcb072bSXin LI lc = ASCII_IS_LOWER(optc); 186a5f0fb15SPaul Saab o = findopt(optc); 187a5f0fb15SPaul Saab } else 188a5f0fb15SPaul Saab { 189a5f0fb15SPaul Saab printopt = optname; 1906dcb072bSXin LI lc = ASCII_IS_LOWER(optname[0]); 191*c77c4889SXin LI o = findopt_name(&optname, NULL, &ambig); 192a5f0fb15SPaul Saab s = optname; 193a5f0fb15SPaul Saab optname = NULL; 194a5f0fb15SPaul Saab if (*s == '\0' || *s == ' ') 195a5f0fb15SPaul Saab { 196a5f0fb15SPaul Saab /* 197a5f0fb15SPaul Saab * The option name matches exactly. 198a5f0fb15SPaul Saab */ 199a5f0fb15SPaul Saab ; 200a5f0fb15SPaul Saab } else if (*s == '=') 201a5f0fb15SPaul Saab { 202a5f0fb15SPaul Saab /* 203a5f0fb15SPaul Saab * The option name is followed by "=value". 204a5f0fb15SPaul Saab */ 205a5f0fb15SPaul Saab if (o != NULL && 206a5f0fb15SPaul Saab (o->otype & OTYPE) != STRING && 207a5f0fb15SPaul Saab (o->otype & OTYPE) != NUMBER) 208a5f0fb15SPaul Saab { 209a5f0fb15SPaul Saab parg.p_string = printopt; 210a5f0fb15SPaul Saab error("The %s option should not be followed by =", 211a5f0fb15SPaul Saab &parg); 2124cc5fc9aSXin LI return; 213a5f0fb15SPaul Saab } 214a5f0fb15SPaul Saab s++; 215a5f0fb15SPaul Saab } else 216a5f0fb15SPaul Saab { 217a5f0fb15SPaul Saab /* 218a5f0fb15SPaul Saab * The specified name is longer than the 219a5f0fb15SPaul Saab * real option name. 220a5f0fb15SPaul Saab */ 221a5f0fb15SPaul Saab o = NULL; 222a5f0fb15SPaul Saab } 223a5f0fb15SPaul Saab } 224a5f0fb15SPaul Saab if (o == NULL) 225a5f0fb15SPaul Saab { 226a5f0fb15SPaul Saab parg.p_string = printopt; 227*c77c4889SXin LI if (ambig) 228a5f0fb15SPaul Saab error("%s is an ambiguous abbreviation (\"less --help\" for help)", 229a5f0fb15SPaul Saab &parg); 230a5f0fb15SPaul Saab else 231a5f0fb15SPaul Saab error("There is no %s option (\"less --help\" for help)", 232a5f0fb15SPaul Saab &parg); 2334cc5fc9aSXin LI return; 234a5f0fb15SPaul Saab } 235a5f0fb15SPaul Saab 236a5f0fb15SPaul Saab str = NULL; 237a5f0fb15SPaul Saab switch (o->otype & OTYPE) 238a5f0fb15SPaul Saab { 239a5f0fb15SPaul Saab case BOOL: 240*c77c4889SXin LI if (o->otype & UNSUPPORTED) 241*c77c4889SXin LI break; 242*c77c4889SXin LI if (o->ovar != NULL) 243*c77c4889SXin LI { 244a5f0fb15SPaul Saab if (set_default) 245a5f0fb15SPaul Saab *(o->ovar) = o->odefault; 246a5f0fb15SPaul Saab else 247a5f0fb15SPaul Saab *(o->ovar) = ! o->odefault; 248*c77c4889SXin LI } 249a5f0fb15SPaul Saab break; 250a5f0fb15SPaul Saab case TRIPLE: 251*c77c4889SXin LI if (o->otype & UNSUPPORTED) 252*c77c4889SXin LI break; 253*c77c4889SXin LI if (o->ovar != NULL) 254*c77c4889SXin LI { 255a5f0fb15SPaul Saab if (set_default) 256a5f0fb15SPaul Saab *(o->ovar) = o->odefault; 257a5f0fb15SPaul Saab else 258a5f0fb15SPaul Saab *(o->ovar) = flip_triple(o->odefault, lc); 259*c77c4889SXin LI } 260a5f0fb15SPaul Saab break; 261a5f0fb15SPaul Saab case STRING: 262a5f0fb15SPaul Saab if (*s == '\0') 263a5f0fb15SPaul Saab { 264a5f0fb15SPaul Saab /* 265a5f0fb15SPaul Saab * Set pendopt and return. 266a5f0fb15SPaul Saab * We will get the string next time 267a5f0fb15SPaul Saab * scan_option is called. 268a5f0fb15SPaul Saab */ 269a5f0fb15SPaul Saab pendopt = o; 270a5f0fb15SPaul Saab return; 271a5f0fb15SPaul Saab } 272a5f0fb15SPaul Saab /* 273a5f0fb15SPaul Saab * Don't do anything here. 274a5f0fb15SPaul Saab * All processing of STRING options is done by 275a5f0fb15SPaul Saab * the handling function. 276a5f0fb15SPaul Saab */ 277000ba3e8STim J. Robbins while (*s == ' ') 278000ba3e8STim J. Robbins s++; 279000ba3e8STim J. Robbins s = optstring(s, &str, printopt, o->odesc[1]); 2804cc5fc9aSXin LI if (s == NULL) 2814cc5fc9aSXin LI return; 282a5f0fb15SPaul Saab break; 283a5f0fb15SPaul Saab case NUMBER: 284a5f0fb15SPaul Saab if (*s == '\0') 285a5f0fb15SPaul Saab { 286a5f0fb15SPaul Saab pendopt = o; 287a5f0fb15SPaul Saab return; 288a5f0fb15SPaul Saab } 289*c77c4889SXin LI if (o->otype & UNSUPPORTED) 290*c77c4889SXin LI break; 291*c77c4889SXin LI *(o->ovar) = getnumc(&s, printopt, NULL); 292a5f0fb15SPaul Saab break; 293a5f0fb15SPaul Saab } 294a5f0fb15SPaul Saab /* 295a5f0fb15SPaul Saab * If the option has a handling function, call it. 296a5f0fb15SPaul Saab */ 297*c77c4889SXin LI if (o->ofunc != NULL && !(o->otype & UNSUPPORTED)) 298a5f0fb15SPaul Saab (*o->ofunc)(INIT, str); 2994cc5fc9aSXin LI if (str != NULL) 3004cc5fc9aSXin LI free(str); 301a5f0fb15SPaul Saab } 302a5f0fb15SPaul Saab } 303a5f0fb15SPaul Saab 304a5f0fb15SPaul Saab /* 305a5f0fb15SPaul Saab * Toggle command line flags from within the program. 306a5f0fb15SPaul Saab * Used by the "-" and "_" commands. 307a5f0fb15SPaul Saab * how_toggle may be: 308a5f0fb15SPaul Saab * OPT_NO_TOGGLE just report the current setting, without changing it. 309a5f0fb15SPaul Saab * OPT_TOGGLE invert the current setting 310a5f0fb15SPaul Saab * OPT_UNSET set to the default value 311a5f0fb15SPaul Saab * OPT_SET set to the inverse of the default value 312a5f0fb15SPaul Saab */ 313*c77c4889SXin LI public void toggle_option(struct loption *o, int lower, constant char *s, int how_toggle) 314a5f0fb15SPaul Saab { 3151ea31627SRobert Watson int num; 316a5f0fb15SPaul Saab int no_prompt; 317*c77c4889SXin LI lbool err; 318a5f0fb15SPaul Saab PARG parg; 319a5f0fb15SPaul Saab 320a5f0fb15SPaul Saab no_prompt = (how_toggle & OPT_NO_PROMPT); 321a5f0fb15SPaul Saab how_toggle &= ~OPT_NO_PROMPT; 322a5f0fb15SPaul Saab 323a5f0fb15SPaul Saab if (o == NULL) 324a5f0fb15SPaul Saab { 32533096f16SXin LI error("No such option", NULL_PARG); 326a5f0fb15SPaul Saab return; 327a5f0fb15SPaul Saab } 328a5f0fb15SPaul Saab 329a5f0fb15SPaul Saab if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) 330a5f0fb15SPaul Saab { 33133096f16SXin LI parg.p_string = opt_desc(o); 332a5f0fb15SPaul Saab error("Cannot change the %s option", &parg); 333a5f0fb15SPaul Saab return; 334a5f0fb15SPaul Saab } 335a5f0fb15SPaul Saab 336a5f0fb15SPaul Saab if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) 337a5f0fb15SPaul Saab { 33833096f16SXin LI parg.p_string = opt_desc(o); 339a5f0fb15SPaul Saab error("Cannot query the %s option", &parg); 340a5f0fb15SPaul Saab return; 341a5f0fb15SPaul Saab } 342a5f0fb15SPaul Saab 343a5f0fb15SPaul Saab /* 344a5f0fb15SPaul Saab * Check for something which appears to be a do_toggle 345a5f0fb15SPaul Saab * (because the "-" command was used), but really is not. 346a5f0fb15SPaul Saab * This could be a string option with no string, or 347a5f0fb15SPaul Saab * a number option with no number. 348a5f0fb15SPaul Saab */ 349a5f0fb15SPaul Saab switch (o->otype & OTYPE) 350a5f0fb15SPaul Saab { 351a5f0fb15SPaul Saab case STRING: 352a5f0fb15SPaul Saab case NUMBER: 353a5f0fb15SPaul Saab if (how_toggle == OPT_TOGGLE && *s == '\0') 354a5f0fb15SPaul Saab how_toggle = OPT_NO_TOGGLE; 355a5f0fb15SPaul Saab break; 356a5f0fb15SPaul Saab } 357a5f0fb15SPaul Saab 358a5f0fb15SPaul Saab #if HILITE_SEARCH 359a5f0fb15SPaul Saab if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 360*c77c4889SXin LI repaint_hilite(FALSE); 361a5f0fb15SPaul Saab #endif 362a5f0fb15SPaul Saab 363a5f0fb15SPaul Saab /* 364a5f0fb15SPaul Saab * Now actually toggle (change) the variable. 365a5f0fb15SPaul Saab */ 366a5f0fb15SPaul Saab if (how_toggle != OPT_NO_TOGGLE) 367a5f0fb15SPaul Saab { 368a5f0fb15SPaul Saab switch (o->otype & OTYPE) 369a5f0fb15SPaul Saab { 370a5f0fb15SPaul Saab case BOOL: 371a5f0fb15SPaul Saab /* 372a5f0fb15SPaul Saab * Boolean. 373a5f0fb15SPaul Saab */ 374*c77c4889SXin LI if (o->ovar != NULL) 375*c77c4889SXin LI { 376a5f0fb15SPaul Saab switch (how_toggle) 377a5f0fb15SPaul Saab { 378a5f0fb15SPaul Saab case OPT_TOGGLE: 379a5f0fb15SPaul Saab *(o->ovar) = ! *(o->ovar); 380a5f0fb15SPaul Saab break; 381a5f0fb15SPaul Saab case OPT_UNSET: 382a5f0fb15SPaul Saab *(o->ovar) = o->odefault; 383a5f0fb15SPaul Saab break; 384a5f0fb15SPaul Saab case OPT_SET: 385a5f0fb15SPaul Saab *(o->ovar) = ! o->odefault; 386a5f0fb15SPaul Saab break; 387a5f0fb15SPaul Saab } 388*c77c4889SXin LI } 389a5f0fb15SPaul Saab break; 390a5f0fb15SPaul Saab case TRIPLE: 391a5f0fb15SPaul Saab /* 392a5f0fb15SPaul Saab * Triple: 393a5f0fb15SPaul Saab * If user gave the lower case letter, then switch 394a5f0fb15SPaul Saab * to 1 unless already 1, in which case make it 0. 395a5f0fb15SPaul Saab * If user gave the upper case letter, then switch 396a5f0fb15SPaul Saab * to 2 unless already 2, in which case make it 0. 397a5f0fb15SPaul Saab */ 398*c77c4889SXin LI if (o->ovar != NULL) 399*c77c4889SXin LI { 400a5f0fb15SPaul Saab switch (how_toggle) 401a5f0fb15SPaul Saab { 402a5f0fb15SPaul Saab case OPT_TOGGLE: 40333096f16SXin LI *(o->ovar) = flip_triple(*(o->ovar), lower); 404a5f0fb15SPaul Saab break; 405a5f0fb15SPaul Saab case OPT_UNSET: 406a5f0fb15SPaul Saab *(o->ovar) = o->odefault; 407a5f0fb15SPaul Saab break; 408a5f0fb15SPaul Saab case OPT_SET: 40933096f16SXin LI *(o->ovar) = flip_triple(o->odefault, lower); 410a5f0fb15SPaul Saab break; 411a5f0fb15SPaul Saab } 412*c77c4889SXin LI } 413a5f0fb15SPaul Saab break; 414a5f0fb15SPaul Saab case STRING: 415a5f0fb15SPaul Saab /* 416a5f0fb15SPaul Saab * String: don't do anything here. 417a5f0fb15SPaul Saab * The handling function will do everything. 418a5f0fb15SPaul Saab */ 419a5f0fb15SPaul Saab switch (how_toggle) 420a5f0fb15SPaul Saab { 421a5f0fb15SPaul Saab case OPT_SET: 422a5f0fb15SPaul Saab case OPT_UNSET: 423a5f0fb15SPaul Saab error("Cannot use \"-+\" or \"--\" for a string option", 424a5f0fb15SPaul Saab NULL_PARG); 425a5f0fb15SPaul Saab return; 426a5f0fb15SPaul Saab } 427a5f0fb15SPaul Saab break; 428a5f0fb15SPaul Saab case NUMBER: 429a5f0fb15SPaul Saab /* 430a5f0fb15SPaul Saab * Number: set the variable to the given number. 431a5f0fb15SPaul Saab */ 432a5f0fb15SPaul Saab switch (how_toggle) 433a5f0fb15SPaul Saab { 434a5f0fb15SPaul Saab case OPT_TOGGLE: 435*c77c4889SXin LI num = getnumc(&s, NULL, &err); 436a5f0fb15SPaul Saab if (!err) 437a5f0fb15SPaul Saab *(o->ovar) = num; 438a5f0fb15SPaul Saab break; 439a5f0fb15SPaul Saab case OPT_UNSET: 440a5f0fb15SPaul Saab *(o->ovar) = o->odefault; 441a5f0fb15SPaul Saab break; 442a5f0fb15SPaul Saab case OPT_SET: 443a5f0fb15SPaul Saab error("Can't use \"-!\" for a numeric option", 444a5f0fb15SPaul Saab NULL_PARG); 445a5f0fb15SPaul Saab return; 446a5f0fb15SPaul Saab } 447a5f0fb15SPaul Saab break; 448a5f0fb15SPaul Saab } 449a5f0fb15SPaul Saab } 450a5f0fb15SPaul Saab 451a5f0fb15SPaul Saab /* 452a5f0fb15SPaul Saab * Call the handling function for any special action 453a5f0fb15SPaul Saab * specific to this option. 454a5f0fb15SPaul Saab */ 455a5f0fb15SPaul Saab if (o->ofunc != NULL) 456a5f0fb15SPaul Saab (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); 457a5f0fb15SPaul Saab 458a5f0fb15SPaul Saab #if HILITE_SEARCH 459a5f0fb15SPaul Saab if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 460a5f0fb15SPaul Saab chg_hilite(); 461a5f0fb15SPaul Saab #endif 462a5f0fb15SPaul Saab 463a5f0fb15SPaul Saab if (!no_prompt) 464a5f0fb15SPaul Saab { 465a5f0fb15SPaul Saab /* 466a5f0fb15SPaul Saab * Print a message describing the new setting. 467a5f0fb15SPaul Saab */ 468a5f0fb15SPaul Saab switch (o->otype & OTYPE) 469a5f0fb15SPaul Saab { 470a5f0fb15SPaul Saab case BOOL: 471a5f0fb15SPaul Saab case TRIPLE: 472a5f0fb15SPaul Saab /* 473a5f0fb15SPaul Saab * Print the odesc message. 474a5f0fb15SPaul Saab */ 475*c77c4889SXin LI if (o->ovar != NULL) 476a5f0fb15SPaul Saab error(o->odesc[*(o->ovar)], NULL_PARG); 477a5f0fb15SPaul Saab break; 478a5f0fb15SPaul Saab case NUMBER: 479a5f0fb15SPaul Saab /* 480a5f0fb15SPaul Saab * The message is in odesc[1] and has a %d for 481a5f0fb15SPaul Saab * the value of the variable. 482a5f0fb15SPaul Saab */ 483a5f0fb15SPaul Saab parg.p_int = *(o->ovar); 484a5f0fb15SPaul Saab error(o->odesc[1], &parg); 485a5f0fb15SPaul Saab break; 486a5f0fb15SPaul Saab case STRING: 487a5f0fb15SPaul Saab /* 488a5f0fb15SPaul Saab * Message was already printed by the handling function. 489a5f0fb15SPaul Saab */ 490a5f0fb15SPaul Saab break; 491a5f0fb15SPaul Saab } 492a5f0fb15SPaul Saab } 493a5f0fb15SPaul Saab 494a5f0fb15SPaul Saab if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 495*c77c4889SXin LI screen_trashed(); 496a5f0fb15SPaul Saab } 497a5f0fb15SPaul Saab 498a5f0fb15SPaul Saab /* 499a5f0fb15SPaul Saab * "Toggle" a triple-valued option. 500a5f0fb15SPaul Saab */ 501d713e089SXin LI static int flip_triple(int val, int lc) 502a5f0fb15SPaul Saab { 503a5f0fb15SPaul Saab if (lc) 504a5f0fb15SPaul Saab return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 505a5f0fb15SPaul Saab else 506a5f0fb15SPaul Saab return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 507a5f0fb15SPaul Saab } 508a5f0fb15SPaul Saab 509a5f0fb15SPaul Saab /* 51033096f16SXin LI * Determine if an option takes a parameter. 511a5f0fb15SPaul Saab */ 512d713e089SXin LI public int opt_has_param(struct loption *o) 513a5f0fb15SPaul Saab { 514a5f0fb15SPaul Saab if (o == NULL) 51533096f16SXin LI return (0); 51633096f16SXin LI if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) 51733096f16SXin LI return (0); 51833096f16SXin LI return (1); 519a5f0fb15SPaul Saab } 520a5f0fb15SPaul Saab 521a5f0fb15SPaul Saab /* 522a5f0fb15SPaul Saab * Return the prompt to be used for a given option letter. 523a5f0fb15SPaul Saab * Only string and number valued options have prompts. 524a5f0fb15SPaul Saab */ 525*c77c4889SXin LI public constant char * opt_prompt(struct loption *o) 526a5f0fb15SPaul Saab { 527a5f0fb15SPaul Saab if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 52833096f16SXin LI return ("?"); 529a5f0fb15SPaul Saab return (o->odesc[0]); 530a5f0fb15SPaul Saab } 531a5f0fb15SPaul Saab 532a5f0fb15SPaul Saab /* 5336f26c71dSXin LI * If the specified option can be toggled, return NULL. 5346f26c71dSXin LI * Otherwise return an appropriate error message. 5356f26c71dSXin LI */ 536*c77c4889SXin LI public constant char * opt_toggle_disallowed(int c) 5376f26c71dSXin LI { 5386f26c71dSXin LI switch (c) 5396f26c71dSXin LI { 5406f26c71dSXin LI case 'o': 5416f26c71dSXin LI if (ch_getflags() & CH_CANSEEK) 5426f26c71dSXin LI return "Input is not a pipe"; 5436f26c71dSXin LI break; 5446f26c71dSXin LI } 5456f26c71dSXin LI return NULL; 5466f26c71dSXin LI } 5476f26c71dSXin LI 5486f26c71dSXin LI /* 549a5f0fb15SPaul Saab * Return whether or not there is a string option pending; 550a5f0fb15SPaul Saab * that is, if the previous option was a string-valued option letter 551a5f0fb15SPaul Saab * (like -P) without a following string. 552a5f0fb15SPaul Saab * In that case, the current option is taken to be the string for 553a5f0fb15SPaul Saab * the previous option. 554a5f0fb15SPaul Saab */ 555*c77c4889SXin LI public lbool isoptpending(void) 556a5f0fb15SPaul Saab { 557a5f0fb15SPaul Saab return (pendopt != NULL); 558a5f0fb15SPaul Saab } 559a5f0fb15SPaul Saab 560a5f0fb15SPaul Saab /* 561a5f0fb15SPaul Saab * Print error message about missing string. 562a5f0fb15SPaul Saab */ 563*c77c4889SXin LI static void nostring(constant char *printopt) 564a5f0fb15SPaul Saab { 565a5f0fb15SPaul Saab PARG parg; 566a5f0fb15SPaul Saab parg.p_string = printopt; 567a5f0fb15SPaul Saab error("Value is required after %s", &parg); 568a5f0fb15SPaul Saab } 569a5f0fb15SPaul Saab 570a5f0fb15SPaul Saab /* 571a5f0fb15SPaul Saab * Print error message if a STRING type option is not followed by a string. 572a5f0fb15SPaul Saab */ 573d713e089SXin LI public void nopendopt(void) 574a5f0fb15SPaul Saab { 57533096f16SXin LI nostring(opt_desc(pendopt)); 576a5f0fb15SPaul Saab } 577a5f0fb15SPaul Saab 578a5f0fb15SPaul Saab /* 579a5f0fb15SPaul Saab * Scan to end of string or to an END_OPTION_STRING character. 580a5f0fb15SPaul Saab * In the latter case, replace the char with a null char. 581a5f0fb15SPaul Saab * Return a pointer to the remainder of the string, if any. 582*c77c4889SXin LI * validchars is of the form "[-][.]d[,]". 583*c77c4889SXin LI * "-" means an optional leading "-" is allowed 584*c77c4889SXin LI * "." means an optional leading "." is allowed (after any "-") 585*c77c4889SXin LI * "d" indicates a string of one or more digits (0-9) 586*c77c4889SXin LI * "," indicates a comma-separated list of digit strings is allowed 587*c77c4889SXin LI * "s" means a space char terminates the argument 588a5f0fb15SPaul Saab */ 589*c77c4889SXin LI static constant char * optstring(constant char *s, char **p_str, constant char *printopt, constant char *validchars) 590a5f0fb15SPaul Saab { 591*c77c4889SXin LI constant char *p; 5921ea31627SRobert Watson char *out; 593a5f0fb15SPaul Saab 594a5f0fb15SPaul Saab if (*s == '\0') 595a5f0fb15SPaul Saab { 596a5f0fb15SPaul Saab nostring(printopt); 5974cc5fc9aSXin LI return (NULL); 598a5f0fb15SPaul Saab } 5994cc5fc9aSXin LI /* Alloc could be more than needed, but not worth trimming. */ 6004cc5fc9aSXin LI *p_str = (char *) ecalloc(strlen(s)+1, sizeof(char)); 6014cc5fc9aSXin LI out = *p_str; 6024cc5fc9aSXin LI 603a5f0fb15SPaul Saab for (p = s; *p != '\0'; p++) 604000ba3e8STim J. Robbins { 6057bd2567cSXin LI if (opt_use_backslash && *p == '\\' && p[1] != '\0') 6064cc5fc9aSXin LI { 6074cc5fc9aSXin LI /* Take next char literally. */ 6084cc5fc9aSXin LI ++p; 6094cc5fc9aSXin LI } else 6104cc5fc9aSXin LI { 611*c77c4889SXin LI if (validchars != NULL) 612*c77c4889SXin LI { 613*c77c4889SXin LI if (validchars[0] == 's') 614*c77c4889SXin LI { 615*c77c4889SXin LI if (*p == ' ') 616*c77c4889SXin LI break; 617*c77c4889SXin LI } else if (*p == '-') 618*c77c4889SXin LI { 619*c77c4889SXin LI if (validchars[0] != '-') 620*c77c4889SXin LI break; 621*c77c4889SXin LI ++validchars; 622*c77c4889SXin LI } else if (*p == '.') 623*c77c4889SXin LI { 624*c77c4889SXin LI if (validchars[0] == '-') 625*c77c4889SXin LI ++validchars; 626*c77c4889SXin LI if (validchars[0] != '.') 627*c77c4889SXin LI break; 628*c77c4889SXin LI ++validchars; 629*c77c4889SXin LI } else if (*p == ',') 630*c77c4889SXin LI { 631*c77c4889SXin LI if (validchars[0] == '\0' || validchars[1] != ',') 632*c77c4889SXin LI break; 633*c77c4889SXin LI } else if (*p >= '0' && *p <= '9') 634*c77c4889SXin LI { 635*c77c4889SXin LI while (validchars[0] == '-' || validchars[0] == '.') 636*c77c4889SXin LI ++validchars; 637*c77c4889SXin LI if (validchars[0] != 'd') 638*c77c4889SXin LI break; 639*c77c4889SXin LI } else 640*c77c4889SXin LI break; 641*c77c4889SXin LI } 642*c77c4889SXin LI if (*p == END_OPTION_STRING) 6434cc5fc9aSXin LI /* End of option string. */ 644c9346414SPaul Saab break; 645c9346414SPaul Saab } 6464cc5fc9aSXin LI *out++ = *p; 647000ba3e8STim J. Robbins } 6484cc5fc9aSXin LI *out = '\0'; 649a5f0fb15SPaul Saab return (p); 650a5f0fb15SPaul Saab } 651a5f0fb15SPaul Saab 652a5f0fb15SPaul Saab /* 6537f074f9cSXin LI */ 654*c77c4889SXin LI static int num_error(constant char *printopt, lbool *errp, lbool overflow) 6557f074f9cSXin LI { 6567f074f9cSXin LI PARG parg; 6577f074f9cSXin LI 6587f074f9cSXin LI if (errp != NULL) 6597f074f9cSXin LI { 6607f074f9cSXin LI *errp = TRUE; 6617f074f9cSXin LI return (-1); 6627f074f9cSXin LI } 6637f074f9cSXin LI if (printopt != NULL) 6647f074f9cSXin LI { 6657f074f9cSXin LI parg.p_string = printopt; 666d713e089SXin LI error((overflow 667d713e089SXin LI ? "Number too large in '%s'" 668d713e089SXin LI : "Number is required after %s"), 669d713e089SXin LI &parg); 6707f074f9cSXin LI } 6717f074f9cSXin LI return (-1); 6727f074f9cSXin LI } 6737f074f9cSXin LI 6747f074f9cSXin LI /* 675a5f0fb15SPaul Saab * Translate a string into a number. 676a5f0fb15SPaul Saab * Like atoi(), but takes a pointer to a char *, and updates 677a5f0fb15SPaul Saab * the char * to point after the translated number. 678a5f0fb15SPaul Saab */ 679*c77c4889SXin LI public int getnumc(constant char **sp, constant char *printopt, lbool *errp) 680a5f0fb15SPaul Saab { 681*c77c4889SXin LI constant char *s = *sp; 6821ea31627SRobert Watson int n; 683*c77c4889SXin LI lbool neg; 684a5f0fb15SPaul Saab 685*c77c4889SXin LI s = skipspc(s); 686a5f0fb15SPaul Saab neg = FALSE; 687a5f0fb15SPaul Saab if (*s == '-') 688a5f0fb15SPaul Saab { 689a5f0fb15SPaul Saab neg = TRUE; 690a5f0fb15SPaul Saab s++; 691a5f0fb15SPaul Saab } 692a5f0fb15SPaul Saab if (*s < '0' || *s > '9') 693d713e089SXin LI return (num_error(printopt, errp, FALSE)); 694a5f0fb15SPaul Saab 695*c77c4889SXin LI n = lstrtoic(s, sp, 10); 696d713e089SXin LI if (n < 0) 697d713e089SXin LI return (num_error(printopt, errp, TRUE)); 698a5f0fb15SPaul Saab if (errp != NULL) 699a5f0fb15SPaul Saab *errp = FALSE; 700a5f0fb15SPaul Saab if (neg) 701a5f0fb15SPaul Saab n = -n; 702a5f0fb15SPaul Saab return (n); 703a5f0fb15SPaul Saab } 7047f074f9cSXin LI 705*c77c4889SXin LI public int getnum(char **sp, constant char *printopt, lbool *errp) 706*c77c4889SXin LI { 707*c77c4889SXin LI constant char *cs = *sp; 708*c77c4889SXin LI int r = getnumc(&cs, printopt, errp); 709*c77c4889SXin LI *sp = (char *) cs; 710*c77c4889SXin LI return r; 711*c77c4889SXin LI } 712*c77c4889SXin LI 7137f074f9cSXin LI /* 7147f074f9cSXin LI * Translate a string into a fraction, represented by the part of a 7157f074f9cSXin LI * number which would follow a decimal point. 7167f074f9cSXin LI * The value of the fraction is returned as parts per NUM_FRAC_DENOM. 7177f074f9cSXin LI * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM. 7187f074f9cSXin LI */ 719*c77c4889SXin LI public long getfraction(constant char **sp, constant char *printopt, lbool *errp) 7207f074f9cSXin LI { 721*c77c4889SXin LI constant char *s; 7227f074f9cSXin LI long frac = 0; 7237f074f9cSXin LI int fraclen = 0; 7247f074f9cSXin LI 725*c77c4889SXin LI s = skipspc(*sp); 7267f074f9cSXin LI if (*s < '0' || *s > '9') 727d713e089SXin LI return (num_error(printopt, errp, FALSE)); 7287f074f9cSXin LI 7297f074f9cSXin LI for ( ; *s >= '0' && *s <= '9'; s++) 7307f074f9cSXin LI { 731d713e089SXin LI if (NUM_LOG_FRAC_DENOM <= fraclen) 732d713e089SXin LI continue; 7337f074f9cSXin LI frac = (frac * 10) + (*s - '0'); 7347f074f9cSXin LI fraclen++; 7357f074f9cSXin LI } 7367f074f9cSXin LI while (fraclen++ < NUM_LOG_FRAC_DENOM) 7377f074f9cSXin LI frac *= 10; 7387f074f9cSXin LI *sp = s; 7397f074f9cSXin LI if (errp != NULL) 7407f074f9cSXin LI *errp = FALSE; 7417f074f9cSXin LI return (frac); 7427f074f9cSXin LI } 7437f074f9cSXin LI 744*c77c4889SXin LI /* 745*c77c4889SXin LI * Set the UNSUPPORTED bit in every option listed 746*c77c4889SXin LI * in the LESS_UNSUPPORT environment variable. 747*c77c4889SXin LI */ 748*c77c4889SXin LI public void init_unsupport(void) 749*c77c4889SXin LI { 750*c77c4889SXin LI constant char *s = lgetenv("LESS_UNSUPPORT"); 751*c77c4889SXin LI if (isnullenv(s)) 752*c77c4889SXin LI return; 753*c77c4889SXin LI for (;;) 754*c77c4889SXin LI { 755*c77c4889SXin LI struct loption *opt; 756*c77c4889SXin LI s = skipspc(s); 757*c77c4889SXin LI if (*s == '\0') break; 758*c77c4889SXin LI if (*s == '-' && *++s == '\0') break; 759*c77c4889SXin LI if (*s == '-') /* long option name */ 760*c77c4889SXin LI { 761*c77c4889SXin LI ++s; 762*c77c4889SXin LI opt = findopt_name(&s, NULL, NULL); 763*c77c4889SXin LI } else /* short (single-char) option */ 764*c77c4889SXin LI { 765*c77c4889SXin LI opt = findopt(*s); 766*c77c4889SXin LI if (opt != NULL) ++s; 767*c77c4889SXin LI } 768*c77c4889SXin LI if (opt != NULL) 769*c77c4889SXin LI opt->otype |= UNSUPPORTED; 770*c77c4889SXin LI } 771*c77c4889SXin LI } 7727f074f9cSXin LI 7737f074f9cSXin LI /* 7747f074f9cSXin LI * Get the value of the -e flag. 7757f074f9cSXin LI */ 776d713e089SXin LI public int get_quit_at_eof(void) 7777f074f9cSXin LI { 7787f074f9cSXin LI if (!less_is_more) 7797f074f9cSXin LI return quit_at_eof; 7807f074f9cSXin LI /* When less_is_more is set, the -e flag semantics are different. */ 781a15691bfSXin LI return quit_at_eof ? OPT_ONPLUS : OPT_ON; 7827f074f9cSXin LI } 783