Example #1
0
/* A simplified loop for vi. Don't dispatch key at end.
   Don't recognize minus sign? */
static int
rl_digit_loop1 (void)
{
  int key, c;

  while (1)
    {
      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
      key = c = rl_read_key ();

      if (_rl_keymap[c].type == ISFUNC &&
	  _rl_keymap[c].function == (Function *)rl_universal_argument)
	{
	  rl_numeric_arg *= 4;
	  continue;
	}

      c = UNMETA (c);
      if (digit_p (c))
	{
	  if (rl_explicit_arg)
	    rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
	  else
	    rl_numeric_arg = digit_value (c);
	  rl_explicit_arg = 1;
	}
      else
	{
	  rl_clear_message ();
	  rl_stuff_char (key);
	  break;
	}
    }
  return (0);
}
Example #2
0
int
rl_vi_char_search(int count, int key)
{
#if defined(HANDLE_MULTIBYTE)
  static char *target;
  static int mb_len;
#else
  static char target;
#endif
  static int orig_dir, dir;

  if ((key == ';') || (key == ','))
    dir = ((key == ';') ? orig_dir : -orig_dir);
  else
    {
      if (vi_redoing)
#if defined(HANDLE_MULTIBYTE)
	target = _rl_vi_last_search_mbchar;
#else
	target = (char)_rl_vi_last_search_char;
#endif
      else
	{
#if defined(HANDLE_MULTIBYTE)
	  mb_len = _rl_read_mbchar(_rl_vi_last_search_mbchar, MB_LEN_MAX);
	  target = _rl_vi_last_search_mbchar;
#else
	  RL_SETSTATE(RL_STATE_MOREINPUT);
	  _rl_vi_last_search_char = target = (char)rl_read_key();
	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
#endif
	}

      switch (key)
        {
        case 't':
          orig_dir = dir = FTO;
          break;

        case 'T':
          orig_dir = dir = BTO;
          break;

        case 'f':
          orig_dir = dir = FFIND;
          break;

        case 'F':
          orig_dir = dir = BFIND;
          break;

        default:
          break;
        }
    }
Example #3
0
int
_rl_arg_getchar ()
{
  int c;

  rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
  RL_SETSTATE(RL_STATE_MOREINPUT);
  c = rl_read_key ();
  RL_UNSETSTATE(RL_STATE_MOREINPUT);

  return c;
}
Example #4
0
static int
tui_mld_read_key (const struct match_list_displayer *displayer)
{
  rl_getc_func_t *prev = rl_getc_function;
  int c;

  /* We can't use tui_getc as we need NEWLINE to not get emitted.  */
  rl_getc_function = tui_mld_getc;
  c = rl_read_key ();
  rl_getc_function = prev;
  return c;
}
Example #5
0
/* A simplified loop for vi. Don't dispatch key at end.
   Don't recognize minus sign?
   Should this do rl_save_prompt/rl_restore_prompt? */
static int
rl_digit_loop1(void)
{
  int key, c;

  RL_SETSTATE(RL_STATE_NUMERICARG);
  while (1)
    {
      if (rl_numeric_arg > 1000000)
	{
	  rl_explicit_arg = rl_numeric_arg = 0;
	  rl_ding ();
	  rl_clear_message ();
	  RL_UNSETSTATE(RL_STATE_NUMERICARG);
	  return 1;
	}
      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
      RL_SETSTATE(RL_STATE_MOREINPUT);
      key = c = rl_read_key ();
      RL_UNSETSTATE(RL_STATE_MOREINPUT);

      if (c >= 0 && _rl_keymap[c].type == ISFUNC &&
	  _rl_keymap[c].function == rl_universal_argument)
	{
	  rl_numeric_arg *= 4;
	  continue;
	}

      c = UNMETA (c);
      if (_rl_digit_p (c))
	{
	  if (rl_explicit_arg)
	    rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
	  else
	    rl_numeric_arg = _rl_digit_value (c);
	  rl_explicit_arg = 1;
	}
      else
	{
	  rl_clear_message ();
	  rl_stuff_char (key);
	  break;
	}
    }

  RL_UNSETSTATE(RL_STATE_NUMERICARG);
  return (0);
}
Example #6
0
/* The user must press "y" or "n".  Non-zero return means "y" pressed.
   Comes from readline/complete.c  */
static int
get_y_or_n(void)
{
  int c;

  for (;;)
    {
      c = rl_read_key();
      if ((c == 'y') || (c == 'Y') || (c == ' '))
	return (1);
      if ((c == 'n') || (c == 'N') || (c == RUBOUT))
	return (0);
      if (c == ABORT_CHAR)
	_rl_abort_internal();
      beep();
    }
}
Example #7
0
/* The user must press "y" or "n".  Non-zero return means "y" pressed.
   Comes from readline/complete.c  */
static int
get_y_or_n (void)
{
  extern int _rl_abort_internal ();
  int c;

  for (;;)
    {
      c = rl_read_key ();
      if (c == 'y' || c == 'Y' || c == ' ')
	return (1);
      if (c == 'n' || c == 'N' || c == RUBOUT)
	return (0);
      if (c == ABORT_CHAR)
	_rl_abort_internal ();
      beep ();
    }
}
Example #8
0
static int
cli_mld_read_key (const struct match_list_displayer *displayer)
{
  return rl_read_key ();
}
Example #9
0
//------------------------------------------------------------------------------
static void display_matches(char** matches, int match_count, int max_length)
{
    int i;
    char** new_matches;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    WORD text_attrib;
    HANDLE std_out_handle;
    wchar_t buffer[512];
    int show_matches = 2;

    // The matches need to be processed so needless path information is removed
    // (this is caused by the \ and / hurdles).
    max_length = 0;
    ++match_count;
    new_matches = (char**)calloc(1, match_count * sizeof(char**));
    for (i = 0; i < match_count; ++i)
    {
        int len;
        char* slash = strrchr(matches[i], '\\');
        new_matches[i] = (slash != NULL) ? slash + 1 : matches[i];

        len = (int)strlen(new_matches[i]);
        max_length = len > max_length ? len : max_length;
    }
    --match_count;

    std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(std_out_handle, &csbi);

    // Get the console's current colour settings
    if (g_match_palette[0] == -1)
    {
        // Pick a suitable foreground colour, check fg isn't the same as bg, and set.
        text_attrib = csbi.wAttributes;
        text_attrib ^= 0x08;

        if ((text_attrib & 0xf0) == (text_attrib & 0x0f))
        {
            text_attrib ^= FOREGROUND_INTENSITY;
        }
    }
    else
    {
        text_attrib = csbi.wAttributes & 0xf0;
        text_attrib |= (g_match_palette[0] & 0x0f);
    }

    SetConsoleTextAttribute(std_out_handle, text_attrib);

    // If there's lots of matches, check with the user before displaying them
    // This matches readline's behaviour, which will get skipped (annoyingly)
    if ((rl_completion_query_items > 0) &&
        (match_count >= rl_completion_query_items))
    {
        DWORD written;

        _snwprintf(
            buffer,
            sizeof_array(buffer),
            L"\nDisplay all %d possibilities? (y or n)",
            match_count
        );
        WriteConsoleW(std_out_handle, buffer, wcslen(buffer), &written, NULL);

        while (show_matches > 1)
        {
            int c = rl_read_key();
            switch (c)
            {
            case 'y':
            case 'Y':
            case ' ':
                show_matches = 1;
                break;

            case 'n':
            case 'N':
            case 0x7f:
                show_matches = 0;
                break;
            }
        }
    }

    // Get readline to display the matches. Flush stream so we catch set colours
    update_screen_size();
    if (show_matches > 0)
    {
        rl_display_match_list(new_matches, match_count, max_length);
    }
    else
    {
        rl_crlf();
    }
    fflush(rl_outstream);

    // Reset console colour back to normal.
    SetConsoleTextAttribute(std_out_handle, csbi.wAttributes);
    rl_forced_update_display();
    rl_display_fixed = 1;

    free(new_matches);
}
Example #10
0
File: rl.c Project: HTshandou/clink
//------------------------------------------------------------------------------
static void display_matches(char** matches, int match_count, int longest)
{
    int i;
    char** new_matches;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    WORD text_attrib;
    HANDLE std_out_handle;
    wchar_t buffer[512];
    int show_matches = 2;
    int match_colour;

    // Process matches and recalculate the longest match length.
    new_matches = match_display_filter(matches, match_count);

    longest = 0;
    for (i = 0; i < (match_count + 1); ++i)
    {
        int len = (int)strlen(new_matches[i]);
        longest = (len > longest) ? len : longest;
    }

    std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(std_out_handle, &csbi);

    // Get the console's current colour settings
    match_colour = get_clink_setting_int("match_colour");
    if (match_colour == -1)
    {
        // Pick a suitable foreground colour, check fg isn't the same as bg, and set.
        text_attrib = csbi.wAttributes;
        text_attrib ^= 0x08;

        if ((text_attrib & 0xf0) == (text_attrib & 0x0f))
        {
            text_attrib ^= FOREGROUND_INTENSITY;
        }
    }
    else
    {
        text_attrib = csbi.wAttributes & 0xf0;
        text_attrib |= (match_colour & 0x0f);
    }

    SetConsoleTextAttribute(std_out_handle, text_attrib);

    // If there's lots of matches, check with the user before displaying them
    // This matches readline's behaviour, which will get skipped (annoyingly)
    if ((rl_completion_query_items > 0) &&
        (match_count >= rl_completion_query_items))
    {
        DWORD written;

        _snwprintf(
            buffer,
            sizeof_array(buffer),
            L"\nDisplay all %d possibilities? (y or n)",
            match_count
        );
        WriteConsoleW(std_out_handle, buffer, wcslen(buffer), &written, NULL);

        while (show_matches > 1)
        {
            int c = rl_read_key();
            switch (c)
            {
            case 'y':
            case 'Y':
            case ' ':
                show_matches = 1;
                break;

            case 'n':
            case 'N':
            case 0x7f:
                show_matches = 0;
                break;
            }
        }
    }

    // Get readline to display the matches.
    if (show_matches > 0)
    {
        // Turn of '/' suffix for directories. RL assumes '/', which isn't the
        // case, plus clink uses colours instead.
        int j = _rl_complete_mark_directories;
        _rl_complete_mark_directories = 0;

        rl_display_match_list(new_matches, match_count, longest);

        _rl_complete_mark_directories = j;
    }
    else
    {
        rl_crlf();
    }

    // Reset console colour back to normal.
    SetConsoleTextAttribute(std_out_handle, csbi.wAttributes);
    rl_forced_update_display();
    rl_display_fixed = 1;

    // Tidy up.
    for (i = 0; i < match_count; ++i)
    {
        free(new_matches[i]);
    }
    free(new_matches);
}
Example #11
0
/* Search non-interactively through the history list.  DIR < 0 means to
   search backwards through the history of previous commands; otherwise
   the search is for commands subsequent to the current position in the
   history list.  PCHAR is the character to use for prompting when reading
   the search string; if not specified (0), it defaults to `:'. */
static void
noninc_search (int dir, int pchar)
{
  int saved_point, c, pmtlen;
  char *p;

  maybe_save_line ();
  saved_point = rl_point;

  /* Use the line buffer to read the search string. */
  rl_line_buffer[0] = 0;
  rl_end = rl_point = 0;

  /* XXX - this needs fixing to work with the prompt expansion stuff - XXX */
  pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
  p = xmalloc (2 + pmtlen);
  if (pmtlen)
    strcpy (p, rl_prompt);
  p[pmtlen] = pchar ? pchar : ':';
  p[pmtlen + 1]  = '\0';

  rl_message (p, 0, 0);
  free (p);

  /* Read the search string. */
  while ((c = rl_read_key ()) != '\0')
    {
      switch (c)
	{
	case CTRL('H'):
	case RUBOUT:
	  if (rl_point == 0)
	    {
	      maybe_unsave_line ();
	      rl_clear_message ();
	      rl_point = saved_point;
	      return;
	    }
	  rl_rubout (1, c);
	  break;

	case CTRL('W'):
	  rl_unix_word_rubout (1, c);
	  break;

	case CTRL('U'):
	  rl_unix_line_discard (1, c);
	  break;

	case RETURN:
	case NEWLINE:
	  goto dosearch;
	  /* NOTREACHED */
	  break;

	case CTRL('C'):
	case CTRL('G'):
	  maybe_unsave_line ();
	  rl_clear_message ();
	  rl_point = saved_point;
	  DING ();
	  return;

	default:
	  rl_insert (1, c);
	  break;
	}
      rl_redisplay ();
    }

 dosearch:
  /* If rl_point == 0, we want to re-use the previous search string and
     start from the saved history position.  If there's no previous search
     string, punt. */
  if (rl_point == 0)
    {
      if (!noninc_search_string)
	{
	  DING ();
	  return;
	}
    }
  else
    {
      /* We want to start the search from the current history position. */
      noninc_history_pos = where_history ();
      if (noninc_search_string)
	free (noninc_search_string);
      noninc_search_string = strdup (rl_line_buffer);
    }

  noninc_dosearch (noninc_search_string, dir);
}
Example #12
0
int
rl_vi_domove (int key, int *nextkey)
{
  int c, save;
  int old_end;

  rl_mark = rl_point;
  c = rl_read_key ();
  *nextkey = c;

  if (!member (c, vi_motion))
    {
      if (digit_p (c))
	{
	  save = rl_numeric_arg;
	  rl_numeric_arg = digit_value (c);
	  rl_digit_loop1 ();
	  rl_numeric_arg *= save;
	  c = rl_read_key ();	/* real command */
	  *nextkey = c;
	}
      else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
	{
	  rl_mark = rl_end;
	  rl_beg_of_line (1, c);
	  _rl_vi_last_motion = c;
	  return (0);
	}
      else
	return (-1);
    }

  _rl_vi_last_motion = c;

  /* Append a blank character temporarily so that the motion routines
     work right at the end of the line. */
  old_end = rl_end;
  rl_line_buffer[rl_end++] = ' ';
  rl_line_buffer[rl_end] = '\0';

  _rl_dispatch (c, _rl_keymap);

  /* Remove the blank that we added. */
  rl_end = old_end;
  rl_line_buffer[rl_end] = '\0';
  if (rl_point > rl_end)
    rl_point = rl_end;

  /* No change in position means the command failed. */
  if (rl_mark == rl_point)
    return (-1);

  /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
     word.  If we are not at the end of the line, and we are on a
     non-whitespace character, move back one (presumably to whitespace). */
  if ((to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
      !whitespace (rl_line_buffer[rl_point]))
    rl_point--;

  /* If cw or cW, back up to the end of a word, so the behaviour of ce
     or cE is the actual result.  Brute-force, no subtlety. */
  if (key == 'c' && rl_point >= rl_mark && (to_upper (c) == 'W'))
    {
      /* Don't move farther back than where we started. */
      while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
	rl_point--;

      /* Posix.2 says that if cw or cW moves the cursor towards the end of
	 the line, the character under the cursor should be deleted. */
      if (rl_point == rl_mark)
        rl_point++;
      else
	{
	  /* Move past the end of the word so that the kill doesn't
	     remove the last letter of the previous word.  Only do this
	     if we are not at the end of the line. */
	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
	    rl_point++;
	}
    }

  if (rl_mark < rl_point)
    exchange (rl_point, rl_mark);

  return (0);
}
Example #13
0
void
cmd_getnum(const unsigned long int idx, const unsigned long int spice)
{
	xmlNodePtr	db_node = NULL;
	xmlChar		*key = NULL, *value = NULL, *value_nl = NULL, *line = NULL, *line_randomed = NULL, *tmp = NULL;

	unsigned long int	lines = 0, line_req = 1, value_len = 0, line_len = 0, line_randomed_len = 0, erase_len = 0, i = 0;
	char		rc = 0;
	char		*rand_str = NULL;
	char		**fork_argv = NULL;
	int		child;
	int		pipefd[2];


	db_node = find_key(idx);
	if (db_node) {
		key = xmlGetProp(db_node, BAD_CAST "name");
		value = xmlGetProp(db_node, BAD_CAST "value");
		value_nl = parse_newlines(value, 0);
		xmlFree(value); value = NULL;

		value_len = xmlStrlen(value_nl);

		/* count how many (new)lines are in the string */
		for (i=0; i < value_len; i++)
			if (value_nl[i] == '\n')
				lines++;
		lines++;


#ifndef _READLINE
		/* clear the prompt temporarily */
		if (el_set(e, EL_PROMPT, el_prompt_null) != 0) {
			perror("ERROR: el_set(EL_PROMPT)");
		}
		if (el_set(e, EL_UNBUFFERED, 1) != 0) {
			perror("ERROR: el_set(EL_UNBUFFERED)");

			xmlFree(key); key = NULL;
			xmlFree(value_nl); value_nl = NULL;
			return;
		}
#else
		rl_prep_terminal(1);
#endif

		while (rc != 'q'  &&  rc != 4) {	/* quit for 'q' or EOT */
			if (batchmode)
				puts("");

			printf("[%s] ", key);	/* print the key */

			/* if multiline, prefix the line with a line number */
			if (lines > 1)
				printf("[%lu/%lu] ", line_req, lines);

			/* get a line out from the value */
			line = get_line(value_nl, line_req);
			line_len = xmlStrlen(line);

			if (spice > 0) {	/* if random padding is requested */
				line_randomed_len = line_len + line_len * spice + spice + 1;
				line_randomed = calloc(1, line_randomed_len); malloc_check(line_randomed);

				/* begin with the random string */
				rand_str = get_random_str(spice, 1);
				if (!rand_str) {
					xmlFree(key); key = NULL;
					xmlFree(value_nl); value_nl = NULL;
					xmlFree(line); line = NULL;
					free(line_randomed); line_randomed = NULL;

					return;
				}
				(void) strlcat((char *)line_randomed, rand_str, line_randomed_len);
				free(rand_str); rand_str = NULL;
				for (i = 0; i < line_len; i++) {
					/* append a character from the line */
					tmp = xmlUTF8Strsub(line, i, 1);
					(void) strlcat((char *)line_randomed, (const char *)tmp, line_randomed_len);
					xmlFree(tmp); tmp = NULL;

					/* append a random string */
					rand_str = get_random_str(spice, 1);
					if (!rand_str) {
						xmlFree(key); key = NULL;
						xmlFree(value_nl); value_nl = NULL;
						xmlFree(line); line = NULL;
						free(line_randomed); line_randomed = NULL;

						return;
					}
					(void) strlcat((char *)line_randomed, rand_str, line_randomed_len);
					free(rand_str); rand_str = NULL;
				}
				line_randomed[line_randomed_len - 1] = '\0';

				xmlFree(line); line = NULL;
				line = line_randomed;
			}

			printf("%s", line);
#ifdef _READLINE
			rl_redisplay();
#endif

			if (batchmode) {
				rc = 'q';
				puts("");
			} else {
				/* this is the prompt, after displaying the value */
#ifndef _READLINE
				el_getc(e, &rc);
#else
				rc = rl_read_key();
#endif

				/* erase (overwrite) the previously written value with spaces */
				printf("\r");
				erase_len = ERASE_LEN;
				for (i = 0; i < erase_len; i++)
					putchar(' ');

				printf("\r");


				/* process the keypress */
				switch (rc) {
					/* line forward */
					case 'f':
					case 'n':
					case 'j':
					case '+':
					case ' ':
					case '>':
					case ']':
					case '}':
					case 10:	/* editline */
					case 13:	/* readline */
						if (line_req < lines)
							line_req++;
						break;
					/* line backward */
					case 'b':
					case 'p':
					case 'k':
					case '-':
					case '<':
					case '[':
					case '{':
					case 8:
						if (line_req - 1 > 0)
							line_req--;
						break;
					/* jump to the requested line */
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						if ((unsigned char)(rc - 48) <= lines)
							line_req = rc - 48;
						break;
					case 't':
						/* This is duplicated in cmd_clipboard.c */
						/* Copy value to tmux paste buffer */

						switch (child = fork()) {
							case -1:
								perror("\nERROR: Couldn't fork(2) for tmux(1)");
								break;
							case 0:	/* Child */
								close(0);	/* This is also needed for Editline's UNBUFFERED mode to continue to work properly. */
								close(1);

								if (bio_chain)
									BIO_free_all(bio_chain);

								if (db_params.db_file) {
									if (close(db_params.db_file) == -1) {
										perror("ERROR: child: close(database file)");
										exit(EXIT_FAILURE);
									} else {
										db_params.db_file = -1;
									}
								}

								fork_argv = malloc(5 * sizeof(char *)); malloc_check(fork_argv);
								fork_argv[0] = "tmux";
								fork_argv[1] = "set-buffer";
								fork_argv[2] = "--";
								fork_argv[3] = (char *) line;
								fork_argv[4] = NULL;

								if (execvp(fork_argv[0], fork_argv) == -1)
									dprintf(STDERR_FILENO, "ERROR: tmux: %s\n", strerror(errno));

								quit(EXIT_FAILURE);

								break;
							default: /* Parent */
								rc = 'q';
								break;
						}

						break;
					case 'x':
					case 'X':
						/* This is duplicated in cmd_clipboard.c */
						/* Copy value to X11 clipboard, using xclip(1) */

						pipe(pipefd);

						switch (child = fork()) {
							case -1:
								perror("\nERROR: Couldn't fork(2) for xclip(1)");
								break;
							case 0:	/* Child */
								close(0);	/* This is also needed for Editline's UNBUFFERED mode to continue to work properly. */
								close(1);
								close(pipefd[1]);

								if (bio_chain)
									BIO_free_all(bio_chain);

								if (db_params.db_file) {
									if (close(db_params.db_file) == -1) {
										perror("ERROR: child: close(database file)");
										exit(EXIT_FAILURE);
									} else {
										db_params.db_file = -1;
									}
								}

								fork_argv = malloc(4 * sizeof(char *)); malloc_check(fork_argv);
								fork_argv[0] = "xclip";
								fork_argv[1] = "-selection";
								if (rc == 'x') {
									fork_argv[2] = "primary";
								} else if (rc == 'X') {
									fork_argv[2] = "clipboard";
								}
								fork_argv[3] = NULL;

								/* stdin becomes the read end of the pipe in the child,
								 * and the exec'd process will have the same environment. */
								dup2(pipefd[0], 0);
								if (execvp(fork_argv[0], fork_argv) == -1)
									dprintf(STDERR_FILENO, "ERROR: xclip: %s\n", strerror(errno));

								quit(EXIT_FAILURE);

								break;
							default: /* Parent */
								/* Write the value to the pipe's write end, which will
								 * appear in the child's stdin (pipe's read end). */
								close(pipefd[0]);
								write(pipefd[1], line, line_len);
								close(pipefd[1]);

								rc = 'q';
								break;
						}

						break;
					default:
						break;
				}
			}

			xmlFree(line); line = NULL;
		}

		xmlFree(key); key = NULL;
		xmlFree(value_nl); value_nl = NULL;

#ifndef _READLINE
		/* re-enable the default prompt */
		if (el_set(e, EL_PROMPT, prompt_str) != 0) {
			perror("ERROR: el_set(EL_PROMPT)");
		}
		el_set(e, EL_UNBUFFERED, 0);
#else
		rl_deprep_terminal();
#endif
	} else
		puts("Invalid index!");
} /* cmd_getnum() */
Example #14
0
File: misc.c Project: bminor/bash
/* Process C as part of the current numeric argument.  Return -1 if the
   argument should be aborted, 0 if we should not read any more chars, and
   1 if we should continue to read chars. */
int
_rl_arg_dispatch (_rl_arg_cxt cxt, int c)
{
  int key, r;

  key = c;

  /* If we see a key bound to `universal-argument' after seeing digits,
      it ends the argument but is otherwise ignored. */
  if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
    {
      if ((cxt & NUM_SAWDIGITS) == 0)
	{
	  rl_numeric_arg *= 4;
	  return 1;
	}
      else if (RL_ISSTATE (RL_STATE_CALLBACK))
        {
          _rl_argcxt |= NUM_READONE;
          return 0;	/* XXX */
        }
      else
	{
	  RL_SETSTATE(RL_STATE_MOREINPUT);
	  key = rl_read_key ();
	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
	  rl_restore_prompt ();
	  rl_clear_message ();
	  RL_UNSETSTATE(RL_STATE_NUMERICARG);
	  if (key < 0)
	    return -1;
	  return (_rl_dispatch (key, _rl_keymap));
	}
    }

  c = UNMETA (c);

  if (_rl_digit_p (c))
    {
      r = _rl_digit_value (c);    	
      rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) +  r : r;
      rl_explicit_arg = 1;
      _rl_argcxt |= NUM_SAWDIGITS;
    }
  else if (c == '-' && rl_explicit_arg == 0)
    {
      rl_numeric_arg = 1;
      _rl_argcxt |= NUM_SAWMINUS;
      rl_arg_sign = -1;
    }
  else
    {
      /* Make M-- command equivalent to M--1 command. */
      if ((_rl_argcxt & NUM_SAWMINUS) && rl_numeric_arg == 1 && rl_explicit_arg == 0)
	rl_explicit_arg = 1;
      rl_restore_prompt ();
      rl_clear_message ();
      RL_UNSETSTATE(RL_STATE_NUMERICARG);

      r = _rl_dispatch (key, _rl_keymap);
      if (RL_ISSTATE (RL_STATE_CALLBACK))
	{
	  /* At worst, this will cause an extra redisplay.  Otherwise,
	     we have to wait until the next character comes in. */
	  if (rl_done == 0)
	    (*rl_redisplay_function) ();
	  r = 0;
	}
      return r;
    }

  return 1;
}