option.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 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 2460786Spsstatic struct option *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{ 4260786Sps register struct option *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; 11960786Sps if (*s == '+') 12060786Sps every_first_cmd = save(++s); 12160786Sps else 12260786Sps ungetsc(s); 12360786Sps s = optstring(s, propt('+')); 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 */ 22760786Sps str = s; 22860786Sps s = optstring(s, printopt); 22960786Sps break; 23060786Sps case NUMBER: 23160786Sps if (*s == '\0') 23260786Sps { 23360786Sps pendopt = o; 23460786Sps return; 23560786Sps } 23660786Sps *(o->ovar) = getnum(&s, printopt, (int*)NULL); 23760786Sps break; 23860786Sps } 23960786Sps /* 24060786Sps * If the option has a handling function, call it. 24160786Sps */ 24260786Sps if (o->ofunc != NULL) 24360786Sps (*o->ofunc)(INIT, str); 24460786Sps } 24560786Sps} 24660786Sps 24760786Sps/* 24860786Sps * Toggle command line flags from within the program. 24960786Sps * Used by the "-" and "_" commands. 25060786Sps * how_toggle may be: 25160786Sps * OPT_NO_TOGGLE just report the current setting, without changing it. 25260786Sps * OPT_TOGGLE invert the current setting 25360786Sps * OPT_UNSET set to the default value 25460786Sps * OPT_SET set to the inverse of the default value 25560786Sps */ 25660786Sps public void 25760786Spstoggle_option(c, s, how_toggle) 25860786Sps int c; 25960786Sps char *s; 26060786Sps int how_toggle; 26160786Sps{ 26260786Sps register struct option *o; 26360786Sps register int num; 26460786Sps int no_prompt; 26560786Sps int err; 26660786Sps PARG parg; 26760786Sps 26860786Sps no_prompt = (how_toggle & OPT_NO_PROMPT); 26960786Sps how_toggle &= ~OPT_NO_PROMPT; 27060786Sps 27160786Sps /* 27260786Sps * Look up the option letter in the option table. 27360786Sps */ 27460786Sps o = findopt(c); 27560786Sps if (o == NULL) 27660786Sps { 27760786Sps parg.p_string = propt(c); 27860786Sps error("There is no %s option", &parg); 27960786Sps return; 28060786Sps } 28160786Sps 28260786Sps if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) 28360786Sps { 28460786Sps parg.p_string = propt(c); 28560786Sps error("Cannot change the %s option", &parg); 28660786Sps return; 28760786Sps } 28860786Sps 28960786Sps if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) 29060786Sps { 29160786Sps parg.p_string = propt(c); 29260786Sps error("Cannot query the %s option", &parg); 29360786Sps return; 29460786Sps } 29560786Sps 29660786Sps /* 29760786Sps * Check for something which appears to be a do_toggle 29860786Sps * (because the "-" command was used), but really is not. 29960786Sps * This could be a string option with no string, or 30060786Sps * a number option with no number. 30160786Sps */ 30260786Sps switch (o->otype & OTYPE) 30360786Sps { 30460786Sps case STRING: 30560786Sps case NUMBER: 30660786Sps if (how_toggle == OPT_TOGGLE && *s == '\0') 30760786Sps how_toggle = OPT_NO_TOGGLE; 30860786Sps break; 30960786Sps } 31060786Sps 31160786Sps#if HILITE_SEARCH 31260786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 31360786Sps repaint_hilite(0); 31460786Sps#endif 31560786Sps 31660786Sps /* 31760786Sps * Now actually toggle (change) the variable. 31860786Sps */ 31960786Sps if (how_toggle != OPT_NO_TOGGLE) 32060786Sps { 32160786Sps switch (o->otype & OTYPE) 32260786Sps { 32360786Sps case BOOL: 32460786Sps /* 32560786Sps * Boolean. 32660786Sps */ 32760786Sps switch (how_toggle) 32860786Sps { 32960786Sps case OPT_TOGGLE: 33060786Sps *(o->ovar) = ! *(o->ovar); 33160786Sps break; 33260786Sps case OPT_UNSET: 33360786Sps *(o->ovar) = o->odefault; 33460786Sps break; 33560786Sps case OPT_SET: 33660786Sps *(o->ovar) = ! o->odefault; 33760786Sps break; 33860786Sps } 33960786Sps break; 34060786Sps case TRIPLE: 34160786Sps /* 34260786Sps * Triple: 34360786Sps * If user gave the lower case letter, then switch 34460786Sps * to 1 unless already 1, in which case make it 0. 34560786Sps * If user gave the upper case letter, then switch 34660786Sps * to 2 unless already 2, in which case make it 0. 34760786Sps */ 34860786Sps switch (how_toggle) 34960786Sps { 35060786Sps case OPT_TOGGLE: 35160786Sps *(o->ovar) = flip_triple(*(o->ovar), 35260786Sps islower(c)); 35360786Sps break; 35460786Sps case OPT_UNSET: 35560786Sps *(o->ovar) = o->odefault; 35660786Sps break; 35760786Sps case OPT_SET: 35860786Sps *(o->ovar) = flip_triple(o->odefault, 35960786Sps islower(c)); 36060786Sps break; 36160786Sps } 36260786Sps break; 36360786Sps case STRING: 36460786Sps /* 36560786Sps * String: don't do anything here. 36660786Sps * The handling function will do everything. 36760786Sps */ 36860786Sps switch (how_toggle) 36960786Sps { 37060786Sps case OPT_SET: 37160786Sps case OPT_UNSET: 37260786Sps error("Cannot use \"-+\" or \"--\" for a string option", 37360786Sps NULL_PARG); 37460786Sps return; 37560786Sps } 37660786Sps break; 37760786Sps case NUMBER: 37860786Sps /* 37960786Sps * Number: set the variable to the given number. 38060786Sps */ 38160786Sps switch (how_toggle) 38260786Sps { 38360786Sps case OPT_TOGGLE: 38460786Sps num = getnum(&s, '\0', &err); 38560786Sps if (!err) 38660786Sps *(o->ovar) = num; 38760786Sps break; 38860786Sps case OPT_UNSET: 38960786Sps *(o->ovar) = o->odefault; 39060786Sps break; 39160786Sps case OPT_SET: 39260786Sps error("Can't use \"-!\" for a numeric option", 39360786Sps NULL_PARG); 39460786Sps return; 39560786Sps } 39660786Sps break; 39760786Sps } 39860786Sps } 39960786Sps 40060786Sps /* 40160786Sps * Call the handling function for any special action 40260786Sps * specific to this option. 40360786Sps */ 40460786Sps if (o->ofunc != NULL) 40560786Sps (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); 40660786Sps 40760786Sps#if HILITE_SEARCH 40860786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 40960786Sps chg_hilite(); 41060786Sps#endif 41160786Sps 41260786Sps if (!no_prompt) 41360786Sps { 41460786Sps /* 41560786Sps * Print a message describing the new setting. 41660786Sps */ 41760786Sps switch (o->otype & OTYPE) 41860786Sps { 41960786Sps case BOOL: 42060786Sps case TRIPLE: 42160786Sps /* 42260786Sps * Print the odesc message. 42360786Sps */ 42460786Sps error(o->odesc[*(o->ovar)], NULL_PARG); 42560786Sps break; 42660786Sps case NUMBER: 42760786Sps /* 42860786Sps * The message is in odesc[1] and has a %d for 42960786Sps * the value of the variable. 43060786Sps */ 43160786Sps parg.p_int = *(o->ovar); 43260786Sps error(o->odesc[1], &parg); 43360786Sps break; 43460786Sps case STRING: 43560786Sps /* 43660786Sps * Message was already printed by the handling function. 43760786Sps */ 43860786Sps break; 43960786Sps } 44060786Sps } 44160786Sps 44260786Sps if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 44360786Sps screen_trashed = TRUE; 44460786Sps} 44560786Sps 44660786Sps/* 44760786Sps * "Toggle" a triple-valued option. 44860786Sps */ 44960786Sps static int 45060786Spsflip_triple(val, lc) 45160786Sps int val; 45260786Sps int lc; 45360786Sps{ 45460786Sps if (lc) 45560786Sps return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 45660786Sps else 45760786Sps return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 45860786Sps} 45960786Sps 46060786Sps/* 46160786Sps * Return a string suitable for printing as the "name" of an option. 46260786Sps * For example, if the option letter is 'x', just return "-x". 46360786Sps */ 46460786Sps static char * 46560786Spspropt(c) 46660786Sps int c; 46760786Sps{ 46860786Sps static char buf[8]; 46960786Sps 47060786Sps sprintf(buf, "-%s", prchar(c)); 47160786Sps return (buf); 47260786Sps} 47360786Sps 47460786Sps/* 47560786Sps * Determine if an option is a single character option (BOOL or TRIPLE), 47660786Sps * or if it a multi-character option (NUMBER). 47760786Sps */ 47860786Sps public int 47960786Spssingle_char_option(c) 48060786Sps int c; 48160786Sps{ 48260786Sps register struct option *o; 48360786Sps 48460786Sps o = findopt(c); 48560786Sps if (o == NULL) 48660786Sps return (TRUE); 48760786Sps return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0); 48860786Sps} 48960786Sps 49060786Sps/* 49160786Sps * Return the prompt to be used for a given option letter. 49260786Sps * Only string and number valued options have prompts. 49360786Sps */ 49460786Sps public char * 49560786Spsopt_prompt(c) 49660786Sps int c; 49760786Sps{ 49860786Sps register struct option *o; 49960786Sps 50060786Sps o = findopt(c); 50160786Sps if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 50260786Sps return (NULL); 50360786Sps return (o->odesc[0]); 50460786Sps} 50560786Sps 50660786Sps/* 50760786Sps * Return whether or not there is a string option pending; 50860786Sps * that is, if the previous option was a string-valued option letter 50960786Sps * (like -P) without a following string. 51060786Sps * In that case, the current option is taken to be the string for 51160786Sps * the previous option. 51260786Sps */ 51360786Sps public int 51460786Spsisoptpending() 51560786Sps{ 51660786Sps return (pendopt != NULL); 51760786Sps} 51860786Sps 51960786Sps/* 52060786Sps * Print error message about missing string. 52160786Sps */ 52260786Sps static void 52360786Spsnostring(printopt) 52460786Sps char *printopt; 52560786Sps{ 52660786Sps PARG parg; 52760786Sps parg.p_string = printopt; 52860786Sps error("Value is required after %s", &parg); 52960786Sps} 53060786Sps 53160786Sps/* 53260786Sps * Print error message if a STRING type option is not followed by a string. 53360786Sps */ 53460786Sps public void 53560786Spsnopendopt() 53660786Sps{ 53760786Sps nostring(propt(pendopt->oletter)); 53860786Sps} 53960786Sps 54060786Sps/* 54160786Sps * Scan to end of string or to an END_OPTION_STRING character. 54260786Sps * In the latter case, replace the char with a null char. 54360786Sps * Return a pointer to the remainder of the string, if any. 54460786Sps */ 54560786Sps static char * 54660786Spsoptstring(s, printopt) 54760786Sps char *s; 54860786Sps char *printopt; 54960786Sps{ 55060786Sps register char *p; 55160786Sps 55260786Sps if (*s == '\0') 55360786Sps { 55460786Sps nostring(printopt); 55560786Sps quit(QUIT_ERROR); 55660786Sps } 55760786Sps for (p = s; *p != '\0'; p++) 55860786Sps if (*p == END_OPTION_STRING) 55960786Sps { 56060786Sps *p = '\0'; 56160786Sps return (p+1); 56260786Sps } 56360786Sps return (p); 56460786Sps} 56560786Sps 56660786Sps/* 56760786Sps * Translate a string into a number. 56860786Sps * Like atoi(), but takes a pointer to a char *, and updates 56960786Sps * the char * to point after the translated number. 57060786Sps */ 57160786Sps public int 57260786Spsgetnum(sp, printopt, errp) 57360786Sps char **sp; 57460786Sps char *printopt; 57560786Sps int *errp; 57660786Sps{ 57760786Sps register char *s; 57860786Sps register int n; 57960786Sps register int neg; 58060786Sps PARG parg; 58160786Sps 58260786Sps s = skipsp(*sp); 58360786Sps neg = FALSE; 58460786Sps if (*s == '-') 58560786Sps { 58660786Sps neg = TRUE; 58760786Sps s++; 58860786Sps } 58960786Sps if (*s < '0' || *s > '9') 59060786Sps { 59160786Sps if (errp != NULL) 59260786Sps { 59360786Sps *errp = TRUE; 59460786Sps return (-1); 59560786Sps } 59660786Sps parg.p_string = printopt; 59760786Sps error("Number is required after %s", &parg); 59860786Sps quit(QUIT_ERROR); 59960786Sps } 60060786Sps 60160786Sps n = 0; 60260786Sps while (*s >= '0' && *s <= '9') 60360786Sps n = 10 * n + *s++ - '0'; 60460786Sps *sp = s; 60560786Sps if (errp != NULL) 60660786Sps *errp = FALSE; 60760786Sps if (neg) 60860786Sps n = -n; 60960786Sps return (n); 61060786Sps} 611