aboutsummaryrefslogtreecommitdiff
path: root/command.c
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2011-05-09 18:30:23 +0000
committerXin LI <delphij@FreeBSD.org>2011-05-09 18:30:23 +0000
commited915d8294a373813108148f47b424e1152e4a5d (patch)
tree345f36f8a19a9fdb66be9a0a5676b2c0abc67bae /command.c
parentf4cb5a505fa28e14d4b01e5c934bcf965a1822b6 (diff)
downloadsrc-ed915d8294a373813108148f47b424e1152e4a5d.tar.gz
src-ed915d8294a373813108148f47b424e1152e4a5d.zip
Vendor import of less v443.vendor/less/v443
Notes
Notes: svn path=/vendor/less/dist/; revision=221706 svn path=/vendor/less/v443/; revision=221707; tag=vendor/less/v443
Diffstat (limited to 'command.c')
-rw-r--r--command.c558
1 files changed, 306 insertions, 252 deletions
diff --git a/command.c b/command.c
index 40bf8fd7a819..aa69a47c1522 100644
--- a/command.c
+++ b/command.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1984-2009 Mark Nudelman
+ * Copyright (C) 1984-2011 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -55,8 +55,6 @@ extern int shift_count;
extern int oldbot;
extern int forw_prompt;
-static char ungot[UNGOT_SIZE];
-static char *ungotp = NULL;
#if SHELL_ESCAPE
static char *shellcmd = NULL; /* For holding last shell command for "!!" */
#endif
@@ -64,7 +62,8 @@ static int mca; /* The multicharacter command (action) */
static int search_type; /* The previous type of search */
static LINENUM number; /* The number typed by the user */
static long fraction; /* The fractional part of the number */
-static char optchar;
+static struct loption *curropt;
+static int opt_lower;
static int optflag;
static int optgetname;
static POSITION bottompos;
@@ -73,6 +72,13 @@ static int save_hshift;
static char pipec;
#endif
+struct ungot {
+ struct ungot *ug_next;
+ char ug_char;
+};
+static struct ungot* ungot = NULL;
+static int unget_end = 0;
+
static void multi_search();
/*
@@ -226,8 +232,8 @@ exec_mca()
every_first_cmd = save(cbuf);
break;
case A_OPT_TOGGLE:
- toggle_option(optchar, cbuf, optflag);
- optchar = '\0';
+ toggle_option(curropt, opt_lower, cbuf, optflag);
+ curropt = NULL;
break;
case A_F_BRACKET:
match_brac(cbuf[0], cbuf[1], 1, (int) number);
@@ -280,22 +286,249 @@ exec_mca()
}
/*
- * Add a character to a multi-character command.
+ * Is a character an erase or kill char?
*/
static int
-mca_char(c)
+is_erase_char(c)
+ int c;
+{
+ return (c == erase_char || c == erase2_char || c == kill_char);
+}
+
+/*
+ * Handle the first char of an option (after the initial dash).
+ */
+ static int
+mca_opt_first_char(c)
+{
+ int flag = (optflag & ~OPT_NO_PROMPT);
+ if (flag == OPT_NO_TOGGLE)
+ {
+ switch (c)
+ {
+ case '_':
+ /* "__" = long option name. */
+ optgetname = TRUE;
+ mca_opt_toggle();
+ return (MCA_MORE);
+ }
+ } else
+ {
+ switch (c)
+ {
+ case '+':
+ /* "-+" = UNSET. */
+ optflag = (flag == OPT_UNSET) ?
+ OPT_TOGGLE : OPT_UNSET;
+ mca_opt_toggle();
+ return (MCA_MORE);
+ case '!':
+ /* "-!" = SET */
+ optflag = (flag == OPT_SET) ?
+ OPT_TOGGLE : OPT_SET;
+ mca_opt_toggle();
+ return (MCA_MORE);
+ case CONTROL('P'):
+ optflag ^= OPT_NO_PROMPT;
+ mca_opt_toggle();
+ return (MCA_MORE);
+ case '-':
+ /* "--" = long option name. */
+ optgetname = TRUE;
+ mca_opt_toggle();
+ return (MCA_MORE);
+ }
+ }
+ /* Char was not handled here. */
+ return (NO_MCA);
+}
+
+/*
+ * Add a char to a long option name.
+ * See if we've got a match for an option name yet.
+ * If so, display the complete name and stop
+ * accepting chars until user hits RETURN.
+ */
+ static int
+mca_opt_nonfirst_char(c)
int c;
{
char *p;
- int flag;
- char buf[3];
+ char *oname;
+
+ if (curropt != NULL)
+ {
+ /*
+ * Already have a match for the name.
+ * Don't accept anything but erase/kill.
+ */
+ if (is_erase_char(c))
+ return (MCA_DONE);
+ return (MCA_MORE);
+ }
+ /*
+ * Add char to cmd buffer and try to match
+ * the option name.
+ */
+ if (cmd_char(c) == CC_QUIT)
+ return (MCA_DONE);
+ p = get_cmdbuf();
+ opt_lower = ASCII_IS_LOWER(p[0]);
+ curropt = findopt_name(&p, &oname, NULL);
+ if (curropt != NULL)
+ {
+ /*
+ * Got a match.
+ * Remember the option and
+ * display the full option name.
+ */
+ cmd_reset();
+ mca_opt_toggle();
+ for (p = oname; *p != '\0'; p++)
+ {
+ c = *p;
+ if (!opt_lower && ASCII_IS_LOWER(c))
+ c = ASCII_TO_UPPER(c);
+ if (cmd_char(c) != CC_OK)
+ return (MCA_DONE);
+ }
+ }
+ return (MCA_MORE);
+}
+
+/*
+ * Handle a char of an option toggle command.
+ */
+ static int
+mca_opt_char(c)
+ int c;
+{
PARG parg;
+ /*
+ * This may be a short option (single char),
+ * or one char of a long option name,
+ * or one char of the option parameter.
+ */
+ if (curropt == NULL && len_cmdbuf() == 0)
+ {
+ int ret = mca_opt_first_char(c);
+ if (ret != NO_MCA)
+ return (ret);
+ }
+ if (optgetname)
+ {
+ /* We're getting a long option name. */
+ if (c != '\n' && c != '\r')
+ return (mca_opt_nonfirst_char(c));
+ if (curropt == NULL)
+ {
+ parg.p_string = get_cmdbuf();
+ error("There is no --%s option", &parg);
+ return (MCA_DONE);
+ }
+ optgetname = FALSE;
+ cmd_reset();
+ } else
+ {
+ if (is_erase_char(c))
+ return (NO_MCA);
+ if (curropt != NULL)
+ /* We're getting the option parameter. */
+ return (NO_MCA);
+ curropt = findopt(c);
+ if (curropt == NULL)
+ {
+ parg.p_string = propt(c);
+ error("There is no %s option", &parg);
+ return (MCA_DONE);
+ }
+ }
+ /*
+ * If the option which was entered does not take a
+ * parameter, toggle the option immediately,
+ * so user doesn't have to hit RETURN.
+ */
+ if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
+ !opt_has_param(curropt))
+ {
+ toggle_option(curropt, ASCII_IS_LOWER(c), "", optflag);
+ return (MCA_DONE);
+ }
+ /*
+ * Display a prompt appropriate for the option parameter.
+ */
+ start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0);
+ return (MCA_MORE);
+}
+
+/*
+ * Handle a char of a search command.
+ */
+ static int
+mca_search_char(c)
+ int c;
+{
+ int flag = 0;
+
+ /*
+ * Certain characters as the first char of
+ * the pattern have special meaning:
+ * ! Toggle the NO_MATCH flag
+ * * Toggle the PAST_EOF flag
+ * @ Toggle the FIRST_FILE flag
+ */
+ if (len_cmdbuf() > 0)
+ return (NO_MCA);
+
+ switch (c)
+ {
+ case CONTROL('E'): /* ignore END of file */
+ case '*':
+ if (mca != A_FILTER)
+ flag = SRCH_PAST_EOF;
+ break;
+ case CONTROL('F'): /* FIRST file */
+ case '@':
+ if (mca != A_FILTER)
+ flag = SRCH_FIRST_FILE;
+ break;
+ case CONTROL('K'): /* KEEP position */
+ if (mca != A_FILTER)
+ flag = SRCH_NO_MOVE;
+ break;
+ case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
+ flag = SRCH_NO_REGEX;
+ break;
+ case CONTROL('N'): /* NOT match */
+ case '!':
+ flag = SRCH_NO_MATCH;
+ break;
+ }
+
+ if (flag != 0)
+ {
+ search_type ^= flag;
+ mca_search();
+ return (MCA_MORE);
+ }
+ return (NO_MCA);
+}
+
+/*
+ * Handle a character of a multi-character command.
+ */
+ static int
+mca_char(c)
+ int c;
+{
+ int ret;
+
switch (mca)
{
case 0:
/*
- * Not in a multicharacter command.
+ * We're not in a multicharacter command.
*/
return (NO_MCA);
@@ -318,7 +551,8 @@ mca_char(c)
{
/*
* Not part of the number.
- * Treat as a normal command character.
+ * End the number and treat this char
+ * as a normal command character.
*/
number = cmd_int(&fraction);
mca = 0;
@@ -328,214 +562,26 @@ mca_char(c)
break;
case A_OPT_TOGGLE:
- /*
- * Special case for the TOGGLE_OPTION command.
- * If the option letter which was entered is a
- * single-char option, execute the command immediately,
- * so user doesn't have to hit RETURN.
- * If the first char is + or -, this indicates
- * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE.
- * "--" begins inputting a long option name.
- */
- if (optchar == '\0' && len_cmdbuf() == 0)
- {
- flag = (optflag & ~OPT_NO_PROMPT);
- if (flag == OPT_NO_TOGGLE)
- {
- switch (c)
- {
- case '_':
- /* "__" = long option name. */
- optgetname = TRUE;
- mca_opt_toggle();
- return (MCA_MORE);
- }
- } else
- {
- switch (c)
- {
- case '+':
- /* "-+" = UNSET. */
- optflag = (flag == OPT_UNSET) ?
- OPT_TOGGLE : OPT_UNSET;
- mca_opt_toggle();
- return (MCA_MORE);
- case '!':
- /* "-!" = SET */
- optflag = (flag == OPT_SET) ?
- OPT_TOGGLE : OPT_SET;
- mca_opt_toggle();
- return (MCA_MORE);
- case CONTROL('P'):
- optflag ^= OPT_NO_PROMPT;
- mca_opt_toggle();
- return (MCA_MORE);
- case '-':
- /* "--" = long option name. */
- optgetname = TRUE;
- mca_opt_toggle();
- return (MCA_MORE);
- }
- }
- }
- if (optgetname)
- {
- /*
- * We're getting a long option name.
- * See if we've matched an option name yet.
- * If so, display the complete name and stop
- * accepting chars until user hits RETURN.
- */
- struct loption *o;
- char *oname;
- int lc;
-
- if (c == '\n' || c == '\r')
- {
- /*
- * When the user hits RETURN, make sure
- * we've matched an option name, then
- * pretend he just entered the equivalent
- * option letter.
- */
- if (optchar == '\0')
- {
- parg.p_string = get_cmdbuf();
- error("There is no --%s option", &parg);
- return (MCA_DONE);
- }
- optgetname = FALSE;
- cmd_reset();
- c = optchar;
- } else
- {
- if (optchar != '\0')
- {
- /*
- * Already have a match for the name.
- * Don't accept anything but erase/kill.
- */
- if (c == erase_char ||
- c == erase2_char ||
- c == kill_char)
- return (MCA_DONE);
- return (MCA_MORE);
- }
- /*
- * Add char to cmd buffer and try to match
- * the option name.
- */
- if (cmd_char(c) == CC_QUIT)
- return (MCA_DONE);
- p = get_cmdbuf();
- lc = ASCII_IS_LOWER(p[0]);
- o = findopt_name(&p, &oname, NULL);
- if (o != NULL)
- {
- /*
- * Got a match.
- * Remember the option letter and
- * display the full option name.
- */
- optchar = o->oletter;
- if (!lc && ASCII_IS_LOWER(optchar))
- optchar = ASCII_TO_UPPER(optchar);
- cmd_reset();
- mca_opt_toggle();
- for (p = oname; *p != '\0'; p++)
- {
- c = *p;
- if (!lc && ASCII_IS_LOWER(c))
- c = ASCII_TO_UPPER(c);
- if (cmd_char(c) != CC_OK)
- return (MCA_DONE);
- }
- }
- return (MCA_MORE);
- }
- } else
- {
- if (c == erase_char || c == erase2_char || c == kill_char)
- break;
- if (optchar != '\0')
- /* We already have the option letter. */
- break;
- }
-
- optchar = c;
- if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
- single_char_option(c))
- {
- toggle_option(c, "", optflag);
- return (MCA_DONE);
- }
- /*
- * Display a prompt appropriate for the option letter.
- */
- if ((p = opt_prompt(c)) == NULL)
- {
- buf[0] = '-';
- buf[1] = c;
- buf[2] = '\0';
- p = buf;
- }
- start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0);
- return (MCA_MORE);
+ ret = mca_opt_char(c);
+ if (ret != NO_MCA)
+ return (ret);
+ break;
case A_F_SEARCH:
case A_B_SEARCH:
case A_FILTER:
- /*
- * Special case for search commands.
- * Certain characters as the first char of
- * the pattern have special meaning:
- * ! Toggle the NO_MATCH flag
- * * Toggle the PAST_EOF flag
- * @ Toggle the FIRST_FILE flag
- */
- if (len_cmdbuf() > 0)
- /*
- * Only works for the first char of the pattern.
- */
- break;
+ ret = mca_search_char(c);
+ if (ret != NO_MCA)
+ return (ret);
+ break;
- flag = 0;
- switch (c)
- {
- case CONTROL('E'): /* ignore END of file */
- case '*':
- if (mca != A_FILTER)
- flag = SRCH_PAST_EOF;
- break;
- case CONTROL('F'): /* FIRST file */
- case '@':
- if (mca != A_FILTER)
- flag = SRCH_FIRST_FILE;
- break;
- case CONTROL('K'): /* KEEP position */
- if (mca != A_FILTER)
- flag = SRCH_NO_MOVE;
- break;
- case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
- flag = SRCH_NO_REGEX;
- break;
- case CONTROL('N'): /* NOT match */
- case '!':
- flag = SRCH_NO_MATCH;
- break;
- }
- if (flag != 0)
- {
- search_type ^= flag;
- mca_search();
- return (MCA_MORE);
- }
+ default:
+ /* Other multicharacter command. */
break;
}
/*
- * Any other multicharacter command
- * is terminated by a newline.
+ * The multichar command is terminated by a newline.
*/
if (c == '\n' || c == '\r')
{
@@ -635,7 +681,7 @@ prompt()
{
register char *p;
- if (ungotp != NULL && ungotp > ungot)
+ if (ungot != NULL)
{
/*
* No prompt necessary if commands are from
@@ -725,48 +771,59 @@ dispversion()
public int
getcc()
{
- if (ungotp == NULL)
+ if (unget_end)
+ {
/*
- * Normal case: no ungotten chars, so get one from the user.
+ * We have just run out of ungotten chars.
*/
- return (getchr());
-
- if (ungotp > ungot)
+ unget_end = 0;
+ if (len_cmdbuf() == 0 || !empty_screen())
+ return (getchr());
/*
- * Return the next ungotten char.
+ * Command is incomplete, so try to complete it.
*/
- return (*--ungotp);
+ switch (mca)
+ {
+ case A_DIGIT:
+ /*
+ * We have a number but no command. Treat as #g.
+ */
+ return ('g');
- /*
- * We have just run out of ungotten chars.
- */
- ungotp = NULL;
- if (len_cmdbuf() == 0 || !empty_screen())
- return (getchr());
- /*
- * Command is incomplete, so try to complete it.
- */
- switch (mca)
- {
- case A_DIGIT:
- /*
- * We have a number but no command. Treat as #g.
- */
- return ('g');
+ case A_F_SEARCH:
+ case A_B_SEARCH:
+ /*
+ * We have "/string" but no newline. Add the \n.
+ */
+ return ('\n');
- case A_F_SEARCH:
- case A_B_SEARCH:
- /*
- * We have "/string" but no newline. Add the \n.
- */
- return ('\n');
+ default:
+ /*
+ * Some other incomplete command. Let user complete it.
+ */
+ return (getchr());
+ }
+ }
- default:
+ if (ungot == NULL)
+ {
/*
- * Some other incomplete command. Let user complete it.
+ * Normal case: no ungotten chars, so get one from the user.
*/
return (getchr());
}
+
+ /*
+ * Return the next ungotten char.
+ */
+ {
+ struct ungot *ug = ungot;
+ char c = ug->ug_char;
+ ungot = ug->ug_next;
+ free(ug);
+ unget_end = (ungot == NULL);
+ return (c);
+ }
}
/*
@@ -777,14 +834,11 @@ getcc()
ungetcc(c)
int c;
{
- if (ungotp == NULL)
- ungotp = ungot;
- if (ungotp >= ungot + sizeof(ungot))
- {
- error("ungetcc overflow", NULL_PARG);
- quit(QUIT_ERROR);
- }
- *ungotp++ = c;
+ struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot));
+
+ ug->ug_char = c;
+ ug->ug_next = ungot;
+ ungot = ug;
}
/*
@@ -927,7 +981,7 @@ commands()
mca = 0;
cmd_accept();
number = 0;
- optchar = '\0';
+ curropt = NULL;
/*
* See if any signals need processing.