option.c revision 128345
160786Sps/* 2128345Stjr * Copyright (C) 1984-2002 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Process command line options. 1460786Sps * 1560786Sps * Each option is a single letter which controls a program variable. 1660786Sps * The options have defaults which may be changed via 1760786Sps * the command line option, toggled via the "-" command, 1860786Sps * or queried via the "_" command. 1960786Sps */ 2060786Sps 2160786Sps#include "less.h" 2260786Sps#include "option.h" 2360786Sps 24128345Stjrstatic struct loption *pendopt; 2560786Spspublic int plusoption = FALSE; 2660786Sps 2760786Spsstatic char *propt(); 2860786Spsstatic char *optstring(); 2960786Spsstatic int flip_triple(); 3060786Sps 3160786Spsextern int screen_trashed; 3260786Spsextern char *every_first_cmd; 3360786Sps 3460786Sps/* 3560786Sps * Scan an argument (either from the command line or from the 3660786Sps * LESS environment variable) and process it. 3760786Sps */ 3860786Sps public void 3960786Spsscan_option(s) 4060786Sps char *s; 4160786Sps{ 42128345Stjr register struct loption *o; 4360786Sps register int optc; 4460786Sps char *optname; 4560786Sps char *printopt; 4660786Sps char *str; 4760786Sps int set_default; 4860786Sps int lc; 4960786Sps int err; 5060786Sps PARG parg; 5160786Sps 5260786Sps if (s == NULL) 5360786Sps return; 5460786Sps 5560786Sps /* 5660786Sps * If we have a pending option which requires an argument, 5760786Sps * handle it now. 5860786Sps * This happens if the previous option was, for example, "-P" 5960786Sps * without a following string. In that case, the current 6060786Sps * option is simply the argument for the previous option. 6160786Sps */ 6260786Sps if (pendopt != NULL) 6360786Sps { 6460786Sps switch (pendopt->otype & OTYPE) 6560786Sps { 6660786Sps case STRING: 6760786Sps (*pendopt->ofunc)(INIT, s); 6860786Sps break; 6960786Sps case NUMBER: 7060786Sps printopt = propt(pendopt->oletter); 7160786Sps *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); 7260786Sps break; 7360786Sps } 7460786Sps pendopt = NULL; 7560786Sps return; 7660786Sps } 7760786Sps 7860786Sps set_default = FALSE; 7960786Sps optname = NULL; 8060786Sps 8160786Sps while (*s != '\0') 8260786Sps { 8360786Sps /* 8460786Sps * Check some special cases first. 8560786Sps */ 8660786Sps switch (optc = *s++) 8760786Sps { 8860786Sps case ' ': 8960786Sps case '\t': 9060786Sps case END_OPTION_STRING: 9160786Sps continue; 9260786Sps case '-': 9360786Sps /* 9460786Sps * "--" indicates an option name instead of a letter. 9560786Sps */ 9660786Sps if (*s == '-') 9760786Sps { 9860786Sps optname = ++s; 9960786Sps break; 10060786Sps } 10160786Sps /* 10260786Sps * "-+" means set these options back to their defaults. 10360786Sps * (They may have been set otherwise by previous 10460786Sps * options.) 10560786Sps */ 10660786Sps set_default = (*s == '+'); 10760786Sps if (set_default) 10860786Sps s++; 10960786Sps continue; 11060786Sps case '+': 11160786Sps /* 11260786Sps * An option prefixed by a "+" is ungotten, so 11360786Sps * that it is interpreted as less commands 11460786Sps * processed at the start of the first input file. 11560786Sps * "++" means process the commands at the start of 11660786Sps * EVERY input file. 11760786Sps */ 11860786Sps plusoption = TRUE; 119128345Stjr s = optstring(s, &str, propt('+'), NULL); 12089019Sps if (*str == '+') 12189019Sps every_first_cmd = save(++str); 12260786Sps else 12389019Sps ungetsc(str); 12460786Sps continue; 12560786Sps case '0': case '1': case '2': case '3': case '4': 12660786Sps case '5': case '6': case '7': case '8': case '9': 12760786Sps /* 12860786Sps * Special "more" compatibility form "-<number>" 12960786Sps * instead of -z<number> to set the scrolling 13060786Sps * window size. 13160786Sps */ 13260786Sps s--; 13360786Sps optc = 'z'; 13460786Sps break; 13560786Sps } 13660786Sps 13760786Sps /* 13860786Sps * Not a special case. 13960786Sps * Look up the option letter in the option table. 14060786Sps */ 14160786Sps err = 0; 14260786Sps if (optname == NULL) 14360786Sps { 14460786Sps printopt = propt(optc); 14560786Sps lc = SIMPLE_IS_LOWER(optc); 14660786Sps o = findopt(optc); 14760786Sps } else 14860786Sps { 14960786Sps printopt = optname; 15060786Sps lc = SIMPLE_IS_LOWER(optname[0]); 15160786Sps o = findopt_name(&optname, NULL, &err); 15260786Sps s = optname; 15360786Sps optname = NULL; 15460786Sps if (*s == '\0' || *s == ' ') 15560786Sps { 15660786Sps /* 15760786Sps * The option name matches exactly. 15860786Sps */ 15960786Sps ; 16060786Sps } else if (*s == '=') 16160786Sps { 16260786Sps /* 16360786Sps * The option name is followed by "=value". 16460786Sps */ 16560786Sps if (o != NULL && 16660786Sps (o->otype & OTYPE) != STRING && 16760786Sps (o->otype & OTYPE) != NUMBER) 16860786Sps { 16960786Sps parg.p_string = printopt; 17060786Sps error("The %s option should not be followed by =", 17160786Sps &parg); 17260786Sps quit(QUIT_ERROR); 17360786Sps } 17460786Sps s++; 17560786Sps } else 17660786Sps { 17760786Sps /* 17860786Sps * The specified name is longer than the 17960786Sps * real option name. 18060786Sps */ 18160786Sps o = NULL; 18260786Sps } 18360786Sps } 18460786Sps if (o == NULL) 18560786Sps { 18660786Sps parg.p_string = printopt; 18760786Sps if (err == OPT_AMBIG) 18860786Sps error("%s is an ambiguous abbreviation (\"less --help\" for help)", 18960786Sps &parg); 19060786Sps else 19160786Sps error("There is no %s option (\"less --help\" for help)", 19260786Sps &parg); 19360786Sps quit(QUIT_ERROR); 19460786Sps } 19560786Sps 19660786Sps str = NULL; 19760786Sps switch (o->otype & OTYPE) 19860786Sps { 19960786Sps case BOOL: 20060786Sps if (set_default) 20160786Sps *(o->ovar) = o->odefault; 20260786Sps else 20360786Sps *(o->ovar) = ! o->odefault; 20460786Sps break; 20560786Sps case TRIPLE: 20660786Sps if (set_default) 20760786Sps *(o->ovar) = o->odefault; 20860786Sps else 20960786Sps *(o->ovar) = flip_triple(o->odefault, lc); 21060786Sps break; 21160786Sps case STRING: 21260786Sps if (*s == '\0') 21360786Sps { 21460786Sps /* 21560786Sps * Set pendopt and return. 21660786Sps * We will get the string next time 21760786Sps * scan_option is called. 21860786Sps */ 21960786Sps pendopt = o; 22060786Sps return; 22160786Sps } 22260786Sps /* 22360786Sps * Don't do anything here. 22460786Sps * All processing of STRING options is done by 22560786Sps * the handling function. 22660786Sps */ 227128345Stjr while (*s == ' ') 228128345Stjr s++; 229128345Stjr s = optstring(s, &str, printopt, o->odesc[1]); 23060786Sps break; 23160786Sps case NUMBER: 23260786Sps if (*s == '\0') 23360786Sps { 23460786Sps pendopt = o; 23560786Sps return; 23660786Sps } 23760786Sps *(o->ovar) = getnum(&s, printopt, (int*)NULL); 23860786Sps break; 23960786Sps } 24060786Sps /* 24160786Sps * If the option has a handling function, call it. 24260786Sps */ 24360786Sps if (o->ofunc != NULL) 24460786Sps (*o->ofunc)(INIT, str); 24560786Sps } 24660786Sps} 24760786Sps 24860786Sps/* 24960786Sps * Toggle command line flags from within the program. 25060786Sps * Used by the "-" and "_" commands. 25160786Sps * how_toggle may be: 25260786Sps * OPT_NO_TOGGLE just report the current setting, without changing it. 25360786Sps * OPT_TOGGLE invert the current setting 25460786Sps * OPT_UNSET set to the default value 25560786Sps * OPT_SET set to the inverse of the default value 25660786Sps */ 25760786Sps public void 25860786Spstoggle_option(c, s, how_toggle) 25960786Sps int c; 26060786Sps char *s; 26160786Sps int how_toggle; 26260786Sps{ 263128345Stjr register struct loption *o; 26460786Sps register int num; 26560786Sps int no_prompt; 26660786Sps int err; 26760786Sps PARG parg; 26860786Sps 26960786Sps no_prompt = (how_toggle & OPT_NO_PROMPT); 27060786Sps how_toggle &= ~OPT_NO_PROMPT; 27160786Sps 27260786Sps /* 27360786Sps * Look up the option letter in the option table. 27460786Sps */ 27560786Sps o = findopt(c); 27660786Sps if (o == NULL) 27760786Sps { 27860786Sps parg.p_string = propt(c); 27960786Sps error("There is no %s option", &parg); 28060786Sps return; 28160786Sps } 28260786Sps 28360786Sps if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) 28460786Sps { 28560786Sps parg.p_string = propt(c); 28660786Sps error("Cannot change the %s option", &parg); 28760786Sps return; 28860786Sps } 28960786Sps 29060786Sps if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) 29160786Sps { 29260786Sps parg.p_string = propt(c); 29360786Sps error("Cannot query the %s option", &parg); 29460786Sps return; 29560786Sps } 29660786Sps 29760786Sps /* 29860786Sps * Check for something which appears to be a do_toggle 29960786Sps * (because the "-" command was used), but really is not. 30060786Sps * This could be a string option with no string, or 30160786Sps * a number option with no number. 30260786Sps */ 30360786Sps switch (o->otype & OTYPE) 30460786Sps { 30560786Sps case STRING: 30660786Sps case NUMBER: 30760786Sps if (how_toggle == OPT_TOGGLE && *s == '\0') 30860786Sps how_toggle = OPT_NO_TOGGLE; 30960786Sps break; 31060786Sps } 31160786Sps 31260786Sps#if HILITE_SEARCH 31360786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 31460786Sps repaint_hilite(0); 31560786Sps#endif 31660786Sps 31760786Sps /* 31860786Sps * Now actually toggle (change) the variable. 31960786Sps */ 32060786Sps if (how_toggle != OPT_NO_TOGGLE) 32160786Sps { 32260786Sps switch (o->otype & OTYPE) 32360786Sps { 32460786Sps case BOOL: 32560786Sps /* 32660786Sps * Boolean. 32760786Sps */ 32860786Sps switch (how_toggle) 32960786Sps { 33060786Sps case OPT_TOGGLE: 33160786Sps *(o->ovar) = ! *(o->ovar); 33260786Sps break; 33360786Sps case OPT_UNSET: 33460786Sps *(o->ovar) = o->odefault; 33560786Sps break; 33660786Sps case OPT_SET: 33760786Sps *(o->ovar) = ! o->odefault; 33860786Sps break; 33960786Sps } 34060786Sps break; 34160786Sps case TRIPLE: 34260786Sps /* 34360786Sps * Triple: 34460786Sps * If user gave the lower case letter, then switch 34560786Sps * to 1 unless already 1, in which case make it 0. 34660786Sps * If user gave the upper case letter, then switch 34760786Sps * to 2 unless already 2, in which case make it 0. 34860786Sps */ 34960786Sps switch (how_toggle) 35060786Sps { 35160786Sps case OPT_TOGGLE: 35260786Sps *(o->ovar) = flip_triple(*(o->ovar), 35360786Sps islower(c)); 35460786Sps break; 35560786Sps case OPT_UNSET: 35660786Sps *(o->ovar) = o->odefault; 35760786Sps break; 35860786Sps case OPT_SET: 35960786Sps *(o->ovar) = flip_triple(o->odefault, 36060786Sps islower(c)); 36160786Sps break; 36260786Sps } 36360786Sps break; 36460786Sps case STRING: 36560786Sps /* 36660786Sps * String: don't do anything here. 36760786Sps * The handling function will do everything. 36860786Sps */ 36960786Sps switch (how_toggle) 37060786Sps { 37160786Sps case OPT_SET: 37260786Sps case OPT_UNSET: 37360786Sps error("Cannot use \"-+\" or \"--\" for a string option", 37460786Sps NULL_PARG); 37560786Sps return; 37660786Sps } 37760786Sps break; 37860786Sps case NUMBER: 37960786Sps /* 38060786Sps * Number: set the variable to the given number. 38160786Sps */ 38260786Sps switch (how_toggle) 38360786Sps { 38460786Sps case OPT_TOGGLE: 385128345Stjr num = getnum(&s, NULL, &err); 38660786Sps if (!err) 38760786Sps *(o->ovar) = num; 38860786Sps break; 38960786Sps case OPT_UNSET: 39060786Sps *(o->ovar) = o->odefault; 39160786Sps break; 39260786Sps case OPT_SET: 39360786Sps error("Can't use \"-!\" for a numeric option", 39460786Sps NULL_PARG); 39560786Sps return; 39660786Sps } 39760786Sps break; 39860786Sps } 39960786Sps } 40060786Sps 40160786Sps /* 40260786Sps * Call the handling function for any special action 40360786Sps * specific to this option. 40460786Sps */ 40560786Sps if (o->ofunc != NULL) 40660786Sps (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); 40760786Sps 40860786Sps#if HILITE_SEARCH 40960786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 41060786Sps chg_hilite(); 41160786Sps#endif 41260786Sps 41360786Sps if (!no_prompt) 41460786Sps { 41560786Sps /* 41660786Sps * Print a message describing the new setting. 41760786Sps */ 41860786Sps switch (o->otype & OTYPE) 41960786Sps { 42060786Sps case BOOL: 42160786Sps case TRIPLE: 42260786Sps /* 42360786Sps * Print the odesc message. 42460786Sps */ 42560786Sps error(o->odesc[*(o->ovar)], NULL_PARG); 42660786Sps break; 42760786Sps case NUMBER: 42860786Sps /* 42960786Sps * The message is in odesc[1] and has a %d for 43060786Sps * the value of the variable. 43160786Sps */ 43260786Sps parg.p_int = *(o->ovar); 43360786Sps error(o->odesc[1], &parg); 43460786Sps break; 43560786Sps case STRING: 43660786Sps /* 43760786Sps * Message was already printed by the handling function. 43860786Sps */ 43960786Sps break; 44060786Sps } 44160786Sps } 44260786Sps 44360786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 44460786Sps screen_trashed = TRUE; 44560786Sps} 44660786Sps 44760786Sps/* 44860786Sps * "Toggle" a triple-valued option. 44960786Sps */ 45060786Sps static int 45160786Spsflip_triple(val, lc) 45260786Sps int val; 45360786Sps int lc; 45460786Sps{ 45560786Sps if (lc) 45660786Sps return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 45760786Sps else 45860786Sps return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 45960786Sps} 46060786Sps 46160786Sps/* 46260786Sps * Return a string suitable for printing as the "name" of an option. 46360786Sps * For example, if the option letter is 'x', just return "-x". 46460786Sps */ 46560786Sps static char * 46660786Spspropt(c) 46760786Sps int c; 46860786Sps{ 46960786Sps static char buf[8]; 47060786Sps 47160786Sps sprintf(buf, "-%s", prchar(c)); 47260786Sps return (buf); 47360786Sps} 47460786Sps 47560786Sps/* 47660786Sps * Determine if an option is a single character option (BOOL or TRIPLE), 47760786Sps * or if it a multi-character option (NUMBER). 47860786Sps */ 47960786Sps public int 48060786Spssingle_char_option(c) 48160786Sps int c; 48260786Sps{ 483128345Stjr register struct loption *o; 48460786Sps 48560786Sps o = findopt(c); 48660786Sps if (o == NULL) 48760786Sps return (TRUE); 48860786Sps return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0); 48960786Sps} 49060786Sps 49160786Sps/* 49260786Sps * Return the prompt to be used for a given option letter. 49360786Sps * Only string and number valued options have prompts. 49460786Sps */ 49560786Sps public char * 49660786Spsopt_prompt(c) 49760786Sps int c; 49860786Sps{ 499128345Stjr register struct loption *o; 50060786Sps 50160786Sps o = findopt(c); 50260786Sps if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 50360786Sps return (NULL); 50460786Sps return (o->odesc[0]); 50560786Sps} 50660786Sps 50760786Sps/* 50860786Sps * Return whether or not there is a string option pending; 50960786Sps * that is, if the previous option was a string-valued option letter 51060786Sps * (like -P) without a following string. 51160786Sps * In that case, the current option is taken to be the string for 51260786Sps * the previous option. 51360786Sps */ 51460786Sps public int 51560786Spsisoptpending() 51660786Sps{ 51760786Sps return (pendopt != NULL); 51860786Sps} 51960786Sps 52060786Sps/* 52160786Sps * Print error message about missing string. 52260786Sps */ 52360786Sps static void 52460786Spsnostring(printopt) 52560786Sps char *printopt; 52660786Sps{ 52760786Sps PARG parg; 52860786Sps parg.p_string = printopt; 52960786Sps error("Value is required after %s", &parg); 53060786Sps} 53160786Sps 53260786Sps/* 53360786Sps * Print error message if a STRING type option is not followed by a string. 53460786Sps */ 53560786Sps public void 53660786Spsnopendopt() 53760786Sps{ 53860786Sps nostring(propt(pendopt->oletter)); 53960786Sps} 54060786Sps 54160786Sps/* 54260786Sps * Scan to end of string or to an END_OPTION_STRING character. 54360786Sps * In the latter case, replace the char with a null char. 54460786Sps * Return a pointer to the remainder of the string, if any. 54560786Sps */ 54660786Sps static char * 547128345Stjroptstring(s, p_str, printopt, validchars) 54860786Sps char *s; 549128345Stjr char **p_str; 55060786Sps char *printopt; 55189019Sps char *validchars; 55260786Sps{ 55360786Sps register char *p; 55460786Sps 55560786Sps if (*s == '\0') 55660786Sps { 55760786Sps nostring(printopt); 55860786Sps quit(QUIT_ERROR); 55960786Sps } 560128345Stjr *p_str = s; 56160786Sps for (p = s; *p != '\0'; p++) 562128345Stjr { 56389019Sps if (*p == END_OPTION_STRING || 56489019Sps (validchars != NULL && strchr(validchars, *p) == NULL)) 56560786Sps { 56689019Sps switch (*p) 56789019Sps { 56889019Sps case END_OPTION_STRING: 56989019Sps case ' ': case '\t': case '-': 570128345Stjr /* Replace the char with a null to terminate string. */ 571128345Stjr *p++ = '\0'; 57289019Sps break; 57389019Sps default: 574128345Stjr /* Cannot replace char; make a copy of the string. */ 575128345Stjr *p_str = (char *) ecalloc(p-s+1, sizeof(char)); 576128345Stjr strncpy(*p_str, s, p-s); 577128345Stjr (*p_str)[p-s] = '\0'; 57889019Sps break; 57989019Sps } 580128345Stjr break; 58160786Sps } 582128345Stjr } 58360786Sps return (p); 58460786Sps} 58560786Sps 58660786Sps/* 58760786Sps * Translate a string into a number. 58860786Sps * Like atoi(), but takes a pointer to a char *, and updates 58960786Sps * the char * to point after the translated number. 59060786Sps */ 59160786Sps public int 59260786Spsgetnum(sp, printopt, errp) 59360786Sps char **sp; 59460786Sps char *printopt; 59560786Sps int *errp; 59660786Sps{ 59760786Sps register char *s; 59860786Sps register int n; 59960786Sps register int neg; 60060786Sps PARG parg; 60160786Sps 60260786Sps s = skipsp(*sp); 60360786Sps neg = FALSE; 60460786Sps if (*s == '-') 60560786Sps { 60660786Sps neg = TRUE; 60760786Sps s++; 60860786Sps } 60960786Sps if (*s < '0' || *s > '9') 61060786Sps { 61160786Sps if (errp != NULL) 61260786Sps { 61360786Sps *errp = TRUE; 61460786Sps return (-1); 61560786Sps } 616128345Stjr if (printopt != NULL) 617128345Stjr { 618128345Stjr parg.p_string = printopt; 619128345Stjr error("Number is required after %s", &parg); 620128345Stjr } 62160786Sps quit(QUIT_ERROR); 62260786Sps } 62360786Sps 62460786Sps n = 0; 62560786Sps while (*s >= '0' && *s <= '9') 62660786Sps n = 10 * n + *s++ - '0'; 62760786Sps *sp = s; 62860786Sps if (errp != NULL) 62960786Sps *errp = FALSE; 63060786Sps if (neg) 63160786Sps n = -n; 63260786Sps return (n); 63360786Sps} 634