Esempio n. 1
0
int read_viminfo_filemark(vir_T *virp, int force)
{
  char_u      *str;
  xfmark_T    *fm;
  int i;

  /* We only get here if line[0] == '\'' or '-'.
   * Illegal mark names are ignored (for future expansion). */
  str = virp->vir_line + 1;
  if (
    *str <= 127 &&
    ((*virp->vir_line == '\'' && (VIM_ISDIGIT(*str) || isupper(*str)))
     || (*virp->vir_line == '-' && *str == '\''))) {
    if (*str == '\'') {
      /* If the jumplist isn't full insert fmark as oldest entry */
      if (curwin->w_jumplistlen == JUMPLISTSIZE)
        fm = NULL;
      else {
        for (i = curwin->w_jumplistlen; i > 0; --i)
          curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
        ++curwin->w_jumplistidx;
        ++curwin->w_jumplistlen;
        fm = &curwin->w_jumplist[0];
        fm->fmark.mark.lnum = 0;
        fm->fname = NULL;
      }
    } else if (VIM_ISDIGIT(*str))
      fm = &namedfm[*str - '0' + NMARKS];
    else
      fm = &namedfm[*str - 'A'];
    if (fm != NULL && (fm->fmark.mark.lnum == 0 || force)) {
      str = skipwhite(str + 1);
      fm->fmark.mark.lnum = getdigits(&str);
      str = skipwhite(str);
      fm->fmark.mark.col = getdigits(&str);
      fm->fmark.mark.coladd = 0;
      fm->fmark.fnum = 0;
      str = skipwhite(str);
      vim_free(fm->fname);
      fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
          FALSE);
    }
  }
  return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
}
Esempio n. 2
0
/// Add the digraphs in the argument to the digraph table.
/// format: {c1}{c2} char {c1}{c2} char ...
///
/// @param str
void putdigraph(char_u *str)
{
  int char1, char2, n;
  int i;
  digr_T *dp;

  while (*str != NUL) {
    str = skipwhite(str);

    if (*str == NUL) {
      return;
    }
    char1 = *str++;
    char2 = *str++;

    if (char2 == 0) {
      EMSG(_(e_invarg));
      return;
    }

    if ((char1 == ESC) || (char2 == ESC)) {
      EMSG(_("E104: Escape not allowed in digraph"));
      return;
    }
    str = skipwhite(str);

    if (!VIM_ISDIGIT(*str)) {
      EMSG(_(e_number_exp));
      return;
    }
    n = getdigits(&str);

    // If the digraph already exists, replace the result.
    dp = (digr_T *)user_digraphs.ga_data;

    for (i = 0; i < user_digraphs.ga_len; ++i) {
      if (((int)dp->char1 == char1) && ((int)dp->char2 == char2)) {
        dp->result = n;
        break;
      }
      ++dp;
    }

    // Add a new digraph to the table.
    if (i == user_digraphs.ga_len) {
      ga_grow(&user_digraphs, 1);
      dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len;
      dp->char1 = char1;
      dp->char2 = char2;
      dp->result = n;
      ++user_digraphs.ga_len;
    }
  }
}
Esempio n. 3
0
/*
 * Decode one item and put it in "res".  If "res" is NULL only advance.
 * Must already have skipped white space.
 *
 * Return FAIL for a decoding error (and give an error).
 * Return MAYBE for an incomplete message.
 */
    static int
json_decode_item(js_read_T *reader, typval_T *res, int options)
{
    char_u	*p;
    int		len;
    int		retval;
    garray_T	stack;
    typval_T	item;
    typval_T	*cur_item;
    json_dec_item_T *top_item;
    char_u	key_buf[NUMBUFLEN];

    ga_init2(&stack, sizeof(json_dec_item_T), 100);
    cur_item = res;
    init_tv(&item);
    if (res != NULL)
    init_tv(res);

    fill_numbuflen(reader);
    p = reader->js_buf + reader->js_used;
    for (;;)
    {
	top_item = NULL;
	if (stack.ga_len > 0)
	{
	    top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
	    json_skip_white(reader);
	    p = reader->js_buf + reader->js_used;
	    if (*p == NUL)
	    {
		retval = MAYBE;
		if (top_item->jd_type == JSON_OBJECT)
		    /* did get the key, clear it */
		    clear_tv(&top_item->jd_key_tv);
		goto theend;
	    }
	    if (top_item->jd_type == JSON_OBJECT_KEY
					    || top_item->jd_type == JSON_ARRAY)
	    {
		/* Check for end of object or array. */
		if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
		{
		    ++reader->js_used; /* consume the ']' or '}' */
		    --stack.ga_len;
		    if (stack.ga_len == 0)
		    {
			retval = OK;
			goto theend;
		    }
		    if (cur_item != NULL)
			cur_item = &top_item->jd_tv;
		    goto item_end;
		}
	    }
	}

	if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
		&& (options & JSON_JS)
		&& reader->js_buf[reader->js_used] != '"'
		&& reader->js_buf[reader->js_used] != '\''
		&& reader->js_buf[reader->js_used] != '['
		&& reader->js_buf[reader->js_used] != '{')
	{
	    char_u *key;

	    /* accept an object key that is not in quotes */
	    key = p = reader->js_buf + reader->js_used;
	    while (*p != NUL && *p != ':' && *p > ' ')
		++p;
	    if (cur_item != NULL)
	    {
		cur_item->v_type = VAR_STRING;
		cur_item->vval.v_string = vim_strnsave(key, (int)(p - key));
		top_item->jd_key = cur_item->vval.v_string;
	    }
	    reader->js_used += (int)(p - key);
	}
	else
	{
	    switch (*p)
	    {
		case '[': /* start of array */
		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
		    {
			retval = FAIL;
			break;
		    }
		    if (ga_grow(&stack, 1) == FAIL)
		    {
			retval = FAIL;
			break;
		    }
		    if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL)
		    {
			cur_item->v_type = VAR_SPECIAL;
			cur_item->vval.v_number = VVAL_NONE;
			retval = FAIL;
			break;
		    }

		    ++reader->js_used; /* consume the '[' */
		    top_item = ((json_dec_item_T *)stack.ga_data)
								+ stack.ga_len;
		    top_item->jd_type = JSON_ARRAY;
		    ++stack.ga_len;
		    if (cur_item != NULL)
		    {
			top_item->jd_tv = *cur_item;
			cur_item = &item;
		    }
		    continue;

		case '{': /* start of object */
		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
		    {
			retval = FAIL;
			break;
		    }
		    if (ga_grow(&stack, 1) == FAIL)
		    {
			retval = FAIL;
			break;
		    }
		    if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL)
		    {
			cur_item->v_type = VAR_SPECIAL;
			cur_item->vval.v_number = VVAL_NONE;
			retval = FAIL;
			break;
		    }

		    ++reader->js_used; /* consume the '{' */
		    top_item = ((json_dec_item_T *)stack.ga_data)
								+ stack.ga_len;
		    top_item->jd_type = JSON_OBJECT_KEY;
		    ++stack.ga_len;
		    if (cur_item != NULL)
		    {
			top_item->jd_tv = *cur_item;
			cur_item = &top_item->jd_key_tv;
		    }
		    continue;

		case '"': /* string */
		    retval = json_decode_string(reader, cur_item, *p);
		    break;

		case '\'':
		    if (options & JSON_JS)
			retval = json_decode_string(reader, cur_item, *p);
		    else
		    {
			EMSG(_(e_invarg));
			retval = FAIL;
		    }
		    break;

		case ',': /* comma: empty item */
		    if ((options & JSON_JS) == 0)
		    {
			EMSG(_(e_invarg));
			retval = FAIL;
			break;
		    }
		    /* FALLTHROUGH */
		case NUL: /* empty */
		    if (cur_item != NULL)
		    {
			cur_item->v_type = VAR_SPECIAL;
			cur_item->vval.v_number = VVAL_NONE;
		    }
		    retval = OK;
		    break;

		default:
		    if (VIM_ISDIGIT(*p) || *p == '-')
		    {
#ifdef FEAT_FLOAT
			char_u  *sp = p;

			if (*sp == '-')
			{
			    ++sp;
			    if (*sp == NUL)
			    {
				retval = MAYBE;
				break;
			    }
			    if (!VIM_ISDIGIT(*sp))
			    {
				EMSG(_(e_invarg));
				retval = FAIL;
				break;
			    }
			}
			sp = skipdigits(sp);
			if (*sp == '.' || *sp == 'e' || *sp == 'E')
			{
			    if (cur_item == NULL)
			    {
				float_T f;

				len = string2float(p, &f);
			    }
			    else
			    {
				cur_item->v_type = VAR_FLOAT;
				len = string2float(p, &cur_item->vval.v_float);
			    }
			}
			else
#endif
			{
			    varnumber_T nr;

			    vim_str2nr(reader->js_buf + reader->js_used,
				    NULL, &len, 0, /* what */
				    &nr, NULL, 0);
			    if (cur_item != NULL)
			    {
				cur_item->v_type = VAR_NUMBER;
				cur_item->vval.v_number = nr;
			    }
			}
			reader->js_used += len;
			retval = OK;
			break;
		    }
		    if (STRNICMP((char *)p, "false", 5) == 0)
		    {
			reader->js_used += 5;
			if (cur_item != NULL)
			{
			    cur_item->v_type = VAR_SPECIAL;
			    cur_item->vval.v_number = VVAL_FALSE;
			}
			retval = OK;
			break;
		    }
		    if (STRNICMP((char *)p, "true", 4) == 0)
		    {
			reader->js_used += 4;
			if (cur_item != NULL)
			{
			    cur_item->v_type = VAR_SPECIAL;
			    cur_item->vval.v_number = VVAL_TRUE;
			}
			retval = OK;
			break;
		    }
		    if (STRNICMP((char *)p, "null", 4) == 0)
		    {
			reader->js_used += 4;
			if (cur_item != NULL)
			{
			    cur_item->v_type = VAR_SPECIAL;
			    cur_item->vval.v_number = VVAL_NULL;
			}
			retval = OK;
			break;
		    }
#ifdef FEAT_FLOAT
		    if (STRNICMP((char *)p, "NaN", 3) == 0)
		    {
			reader->js_used += 3;
			if (cur_item != NULL)
			{
			    cur_item->v_type = VAR_FLOAT;
			    cur_item->vval.v_float = NAN;
			}
			retval = OK;
			break;
		    }
		    if (STRNICMP((char *)p, "Infinity", 8) == 0)
		    {
			reader->js_used += 8;
			if (cur_item != NULL)
			{
			    cur_item->v_type = VAR_FLOAT;
			    cur_item->vval.v_float = INFINITY;
			}
			retval = OK;
			break;
		    }
#endif
		    /* check for truncated name */
		    len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
		    if (
			    (len < 5 && STRNICMP((char *)p, "false", len) == 0)
#ifdef FEAT_FLOAT
			    || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
			    || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
#endif
			    || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
				       ||  STRNICMP((char *)p, "null", len) == 0)))

			retval = MAYBE;
		    else
			retval = FAIL;
		    break;
	    }

	    /* We are finished when retval is FAIL or MAYBE and when at the
	     * toplevel. */
	    if (retval == FAIL)
		break;
	    if (retval == MAYBE || stack.ga_len == 0)
		goto theend;

	    if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
		    && cur_item != NULL)
	    {
		top_item->jd_key = get_tv_string_buf_chk(cur_item, key_buf);
		if (top_item->jd_key == NULL)
		{
		    clear_tv(cur_item);
		    EMSG(_(e_invarg));
		    retval = FAIL;
		    goto theend;
		}
	    }
	}

item_end:
	top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
	switch (top_item->jd_type)
	{
	    case JSON_ARRAY:
		if (res != NULL)
		{
		    listitem_T	*li = listitem_alloc();

		    if (li == NULL)
		    {
			clear_tv(cur_item);
			retval = FAIL;
			goto theend;
		    }
		    li->li_tv = *cur_item;
		    list_append(top_item->jd_tv.vval.v_list, li);
		}
		if (cur_item != NULL)
		    cur_item = &item;

		json_skip_white(reader);
		p = reader->js_buf + reader->js_used;
		if (*p == ',')
		    ++reader->js_used;
		else if (*p != ']')
		{
		    if (*p == NUL)
			retval = MAYBE;
		    else
		    {
			EMSG(_(e_invarg));
			retval = FAIL;
		    }
		    goto theend;
		}
		break;

	    case JSON_OBJECT_KEY:
		json_skip_white(reader);
		p = reader->js_buf + reader->js_used;
		if (*p != ':')
		{
		    if (cur_item != NULL)
			clear_tv(cur_item);
		    if (*p == NUL)
			retval = MAYBE;
		    else
		    {
			EMSG(_(e_invarg));
			retval = FAIL;
		    }
		    goto theend;
		}
		++reader->js_used;
		json_skip_white(reader);
		top_item->jd_type = JSON_OBJECT;
		if (cur_item != NULL)
		    cur_item = &item;
		break;

	    case JSON_OBJECT:
		if (cur_item != NULL
			&& dict_find(top_item->jd_tv.vval.v_dict,
						 top_item->jd_key, -1) != NULL)
		{
		    EMSG2(_("E938: Duplicate key in JSON: \"%s\""),
							     top_item->jd_key);
		    clear_tv(&top_item->jd_key_tv);
		    clear_tv(cur_item);
		    retval = FAIL;
		    goto theend;
		}

		if (cur_item != NULL)
		{
		    dictitem_T *di = dictitem_alloc(top_item->jd_key);

		    clear_tv(&top_item->jd_key_tv);
		    if (di == NULL)
		    {
			clear_tv(cur_item);
			retval = FAIL;
			goto theend;
		    }
		    di->di_tv = *cur_item;
		    di->di_tv.v_lock = 0;
		    if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
		    {
			dictitem_free(di);
			retval = FAIL;
			goto theend;
		    }
		}

		json_skip_white(reader);
		p = reader->js_buf + reader->js_used;
		if (*p == ',')
		    ++reader->js_used;
		else if (*p != '}')
		{
		    if (*p == NUL)
			retval = MAYBE;
		    else
		    {
			EMSG(_(e_invarg));
			retval = FAIL;
		    }
		    goto theend;
		}
		top_item->jd_type = JSON_OBJECT_KEY;
		if (cur_item != NULL)
		    cur_item = &top_item->jd_key_tv;
		break;
	}
    }

    /* Get here when parsing failed. */
    if (res != NULL)
    {
	clear_tv(res);
	res->v_type = VAR_SPECIAL;
	res->vval.v_number = VVAL_NONE;
    }
    EMSG(_(e_invarg));

theend:
    ga_clear(&stack);
    return retval;
}
Esempio n. 4
0
/*
 * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
 * ("what" is SHAPE_MOUSE).
 * Returns error message for an illegal option, NULL otherwise.
 */
char_u *parse_shape_opt(int what)
{
  char_u      *modep;
  char_u      *colonp;
  char_u      *commap;
  char_u      *slashp;
  char_u      *p, *endp;
  int idx = 0;                          /* init for GCC */
  int all_idx;
  int len;
  int i;
  int found_ve = FALSE;                 /* found "ve" flag */
  int round;

  /*
   * First round: check for errors; second round: do it for real.
   */
  for (round = 1; round <= 2; ++round) {
    /*
     * Repeat for all comma separated parts.
     */
    modep = p_guicursor;
    while (*modep != NUL) {
      colonp = vim_strchr(modep, ':');
      if (colonp == NULL)
        return (char_u *)N_("E545: Missing colon");
      if (colonp == modep)
        return (char_u *)N_("E546: Illegal mode");
      commap = vim_strchr(modep, ',');

      /*
       * Repeat for all mode's before the colon.
       * For the 'a' mode, we loop to handle all the modes.
       */
      all_idx = -1;
      assert(modep < colonp);
      while (modep < colonp || all_idx >= 0) {
        if (all_idx < 0) {
          /* Find the mode. */
          if (modep[1] == '-' || modep[1] == ':')
            len = 1;
          else
            len = 2;
          if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
            all_idx = SHAPE_IDX_COUNT - 1;
          else {
            for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
              if (STRNICMP(modep, shape_table[idx].name, len)
                  == 0)
                break;
            if (idx == SHAPE_IDX_COUNT
                || (shape_table[idx].used_for & what) == 0)
              return (char_u *)N_("E546: Illegal mode");
            if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
              found_ve = TRUE;
          }
          modep += len + 1;
        }

        if (all_idx >= 0)
          idx = all_idx--;
        else if (round == 2) {
          {
            /* Set the defaults, for the missing parts */
            shape_table[idx].shape = SHAPE_BLOCK;
            shape_table[idx].blinkwait = 700L;
            shape_table[idx].blinkon = 400L;
            shape_table[idx].blinkoff = 250L;
          }
        }

        /* Parse the part after the colon */
        for (p = colonp + 1; *p && *p != ','; ) {
          {
            /*
             * First handle the ones with a number argument.
             */
            i = *p;
            len = 0;
            if (STRNICMP(p, "ver", 3) == 0)
              len = 3;
            else if (STRNICMP(p, "hor", 3) == 0)
              len = 3;
            else if (STRNICMP(p, "blinkwait", 9) == 0)
              len = 9;
            else if (STRNICMP(p, "blinkon", 7) == 0)
              len = 7;
            else if (STRNICMP(p, "blinkoff", 8) == 0)
              len = 8;
            if (len != 0) {
              p += len;
              if (!VIM_ISDIGIT(*p))
                return (char_u *)N_("E548: digit expected");
              long digits = getdigits(&p);
              assert(digits <= INT_MAX);
              int n = (int)digits;
              if (len == 3) {               /* "ver" or "hor" */
                if (n == 0)
                  return (char_u *)N_("E549: Illegal percentage");
                if (round == 2) {
                  if (TOLOWER_ASC(i) == 'v')
                    shape_table[idx].shape = SHAPE_VER;
                  else
                    shape_table[idx].shape = SHAPE_HOR;
                  shape_table[idx].percentage = n;
                }
              } else if (round == 2) {
                if (len == 9)
                  shape_table[idx].blinkwait = n;
                else if (len == 7)
                  shape_table[idx].blinkon = n;
                else
                  shape_table[idx].blinkoff = n;
              }
            } else if (STRNICMP(p, "block", 5) == 0) {
              if (round == 2)
                shape_table[idx].shape = SHAPE_BLOCK;
              p += 5;
            } else {          /* must be a highlight group name then */
              endp = vim_strchr(p, '-');
              if (commap == NULL) {                         /* last part */
                if (endp == NULL)
                  endp = p + STRLEN(p);                     /* find end of part */
              } else if (endp > commap || endp == NULL)
                endp = commap;
              slashp = vim_strchr(p, '/');
              if (slashp != NULL && slashp < endp) {
                /* "group/langmap_group" */
                i = syn_check_group(p, (int)(slashp - p));
                p = slashp + 1;
              }
              if (round == 2) {
                shape_table[idx].id = syn_check_group(p,
                    (int)(endp - p));
                shape_table[idx].id_lm = shape_table[idx].id;
                if (slashp != NULL && slashp < endp)
                  shape_table[idx].id = i;
              }
              p = endp;
            }
          }           /* if (what != SHAPE_MOUSE) */

          if (*p == '-')
            ++p;
        }
      }
      modep = p;
      if (*modep == ',')
        ++modep;
    }
  }

  /* If the 's' flag is not given, use the 'v' cursor for 's' */
  if (!found_ve) {
    {
      shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
      shape_table[SHAPE_IDX_VE].percentage =
        shape_table[SHAPE_IDX_V].percentage;
      shape_table[SHAPE_IDX_VE].blinkwait =
        shape_table[SHAPE_IDX_V].blinkwait;
      shape_table[SHAPE_IDX_VE].blinkon =
        shape_table[SHAPE_IDX_V].blinkon;
      shape_table[SHAPE_IDX_VE].blinkoff =
        shape_table[SHAPE_IDX_V].blinkoff;
      shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
      shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
    }
  }

  return NULL;
}
Esempio n. 5
0
// Replace any terminal code strings in from[] with the equivalent internal
// vim representation.	This is used for the "from" and "to" part of a
// mapping, and the "to" part of a menu command.
// Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains
// '<'.
// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER.
//
// The replacement is done in result[] and finally copied into allocated
// memory. If this all works well *bufp is set to the allocated memory and a
// pointer to it is returned. If something fails *bufp is set to NULL and from
// is returned.
//
// CTRL-V characters are removed.  When "from_part" is TRUE, a trailing CTRL-V
// is included, otherwise it is removed (for ":map xx ^V", maps xx to
// nothing).  When 'cpoptions' does not contain 'B', a backslash can be used
// instead of a CTRL-V.
char_u * replace_termcodes (
    char_u *from,
    char_u **bufp,
    int from_part,
    int do_lt,                     // also translate <lt>
    int special                    // always accept <key> notation
)
{
  ssize_t i;
  size_t slen;
  char_u key;
  size_t dlen = 0;
  char_u      *src;
  int do_backslash;             // backslash is a special character
  int do_special;               // recognize <> key codes
  char_u      *result;          // buffer for resulting string

  do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
  do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special;

  // Allocate space for the translation.  Worst case a single character is
  // replaced by 6 bytes (shifted special key), plus a NUL at the end.
  result = xmalloc(STRLEN(from) * 6 + 1);

  src = from;

  // Check for #n at start only: function key n
  if (from_part && src[0] == '#' && VIM_ISDIGIT(src[1])) {  // function key
    result[dlen++] = K_SPECIAL;
    result[dlen++] = 'k';
    if (src[1] == '0') {
      result[dlen++] = ';';     // #0 is F10 is "k;"
    } else {
      result[dlen++] = src[1];  // #3 is F3 is "k3"
    }
    src += 2;
  }

  // Copy each byte from *from to result[dlen]
  while (*src != NUL) {
    // If 'cpoptions' does not contain '<', check for special key codes,
    // like "<C-S-LeftMouse>"
    if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0)) {
      // Replace <SID> by K_SNR <script-nr> _.
      // (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
      if (STRNICMP(src, "<SID>", 5) == 0) {
        if (current_SID <= 0) {
          EMSG(_(e_usingsid));
        } else {
          src += 5;
          result[dlen++] = K_SPECIAL;
          result[dlen++] = (int)KS_EXTRA;
          result[dlen++] = (int)KE_SNR;
          sprintf((char *)result + dlen, "%" PRId64, (int64_t)current_SID);
          dlen += STRLEN(result + dlen);
          result[dlen++] = '_';
          continue;
        }
      }

      slen = trans_special(&src, result + dlen, TRUE);
      if (slen) {
        dlen += slen;
        continue;
      }
    }

    if (do_special) {
      char_u  *p, *s, len;

      // Replace <Leader> by the value of "mapleader".
      // Replace <LocalLeader> by the value of "maplocalleader".
      // If "mapleader" or "maplocalleader" isn't set use a backslash.
      if (STRNICMP(src, "<Leader>", 8) == 0) {
        len = 8;
        p = get_var_value((char_u *)"g:mapleader");
      } else if (STRNICMP(src, "<LocalLeader>", 13) == 0)   {
        len = 13;
        p = get_var_value((char_u *)"g:maplocalleader");
      } else {
        len = 0;
        p = NULL;
      }

      if (len != 0) {
        // Allow up to 8 * 6 characters for "mapleader".
        if (p == NULL || *p == NUL || STRLEN(p) > 8 * 6) {
          s = (char_u *)"\\";
        } else {
          s = p;
        }
        while (*s != NUL) {
          result[dlen++] = *s++;
        }
        src += len;
        continue;
      }
    }

    // Remove CTRL-V and ignore the next character.
    // For "from" side the CTRL-V at the end is included, for the "to"
    // part it is removed.
    // If 'cpoptions' does not contain 'B', also accept a backslash.
    key = *src;
    if (key == Ctrl_V || (do_backslash && key == '\\')) {
      ++src;  // skip CTRL-V or backslash
      if (*src == NUL) {
        if (from_part) {
          result[dlen++] = key;
        }
        break;
      }
    }

    // skip multibyte char correctly
    for (i = (*mb_ptr2len)(src); i > 0; --i) {
      // If the character is K_SPECIAL, replace it with K_SPECIAL
      // KS_SPECIAL KE_FILLER.
      // If compiled with the GUI replace CSI with K_CSI.
      if (*src == K_SPECIAL) {
        result[dlen++] = K_SPECIAL;
        result[dlen++] = KS_SPECIAL;
        result[dlen++] = KE_FILLER;
      } else {
        result[dlen++] = *src;
      }
      ++src;
    }
  }
  result[dlen] = NUL;

  *bufp = xrealloc(result, dlen + 1);

  return *bufp;
}
Esempio n. 6
0
/*
 * Try translating a <> name at (*srcp)[], return the key and modifiers.
 * srcp is advanced to after the <> name.
 * returns 0 if there is no match.
 */
int 
find_special_key (
    char_u **srcp,
    int *modp,
    int keycode,                 /* prefer key code, e.g. K_DEL instead of DEL */
    int keep_x_key              /* don't translate xHome to Home key */
)
{
  char_u      *last_dash;
  char_u      *end_of_name;
  char_u      *src;
  char_u      *bp;
  int modifiers;
  int bit;
  int key;
  unsigned long n;
  int l;

  src = *srcp;
  if (src[0] != '<')
    return 0;

  /* Find end of modifier list */
  last_dash = src;
  for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
    if (*bp == '-') {
      last_dash = bp;
      if (bp[1] != NUL) {
        if (has_mbyte)
          l = mb_ptr2len(bp + 1);
        else
          l = 1;
        if (bp[l + 1] == '>')
          bp += l;              /* anything accepted, like <C-?> */
      }
    }
    if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
      bp += 3;          /* skip t_xx, xx may be '-' or '>' */
    else if (STRNICMP(bp, "char-", 5) == 0) {
      vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL);
      bp += l + 5;
      break;
    }
  }

  if (*bp == '>') {     /* found matching '>' */
    end_of_name = bp + 1;

    /* Which modifiers are given? */
    modifiers = 0x0;
    for (bp = src + 1; bp < last_dash; bp++) {
      if (*bp != '-') {
        bit = name_to_mod_mask(*bp);
        if (bit == 0x0)
          break;                /* Illegal modifier name */
        modifiers |= bit;
      }
    }

    /*
     * Legal modifier name.
     */
    if (bp >= last_dash) {
      if (STRNICMP(last_dash + 1, "char-", 5) == 0
          && VIM_ISDIGIT(last_dash[6])) {
        /* <Char-123> or <Char-033> or <Char-0x33> */
        vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n);
        key = (int)n;
      } else {
        /*
         * Modifier with single letter, or special key name.
         */
        if (has_mbyte)
          l = mb_ptr2len(last_dash + 1);
        else
          l = 1;
        if (modifiers != 0 && last_dash[l + 1] == '>')
          key = PTR2CHAR(last_dash + 1);
        else {
          key = get_special_key_code(last_dash + 1);
          if (!keep_x_key)
            key = handle_x_keys(key);
        }
      }

      /*
       * get_special_key_code() may return NUL for invalid
       * special key name.
       */
      if (key != NUL) {
        /*
         * Only use a modifier when there is no special key code that
         * includes the modifier.
         */
        key = simplify_key(key, &modifiers);

        if (!keycode) {
          /* don't want keycode, use single byte code */
          if (key == K_BS)
            key = BS;
          else if (key == K_DEL || key == K_KDEL)
            key = DEL;
        }

        /*
         * Normal Key with modifier: Try to make a single byte code.
         */
        if (!IS_SPECIAL(key))
          key = extract_modifiers(key, &modifiers);

        *modp = modifiers;
        *srcp = end_of_name;
        return key;
      }
    }
  }
  return 0;
}
Esempio n. 7
0
/// Helper for init_chartab
///
/// @param global FALSE: only set buf->b_chartab[]
///
/// @return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has
/// an error, OK otherwise.
int buf_init_chartab(buf_T *buf, int global)
{
  int c;
  int c2;
  char_u *p;
  int i;
  int tilde;
  int do_isalpha;

  if (global) {
    // Set the default size for printable characters:
    // From <Space> to '~' is 1 (printable), others are 2 (not printable).
    // This also inits all 'isident' and 'isfname' flags to FALSE.
    //
    // EBCDIC: all chars below ' ' are not printable, all others are
    // printable.
    c = 0;

    while (c < ' ') {
      chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
    }

    while (c <= '~') {
      chartab[c++] = 1 + CT_PRINT_CHAR;
    }

    if (p_altkeymap) {
      while (c < YE) {
        chartab[c++] = 1 + CT_PRINT_CHAR;
      }
    }

    while (c < 256) {
      if (enc_utf8 && (c >= 0xa0)) {
        // UTF-8: bytes 0xa0 - 0xff are printable (latin1)
        chartab[c++] = CT_PRINT_CHAR + 1;
      } else if ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) {
        // euc-jp characters starting with 0x8e are single width
        chartab[c++] = CT_PRINT_CHAR + 1;
      } else if ((enc_dbcs != 0) && (MB_BYTE2LEN(c) == 2)) {
        // other double-byte chars can be printable AND double-width
        chartab[c++] = CT_PRINT_CHAR + 2;
      } else {
        // the rest is unprintable by default
        chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
      }
    }

    // Assume that every multi-byte char is a filename character.
    for (c = 1; c < 256; ++c) {
      if (((enc_dbcs != 0) && (MB_BYTE2LEN(c) > 1))
          || ((enc_dbcs == DBCS_JPNU) && (c == 0x8e))
          || (enc_utf8 && (c >= 0xa0))) {
        chartab[c] |= CT_FNAME_CHAR;
      }
    }
  }

  // Init word char flags all to FALSE
  memset(buf->b_chartab, 0, (size_t)32);

  if (enc_dbcs != 0) {
    for (c = 0; c < 256; ++c) {
      // double-byte characters are probably word characters
      if (MB_BYTE2LEN(c) == 2) {
        SET_CHARTAB(buf, c);
      }
    }
  }

  // In lisp mode the '-' character is included in keywords.
  if (buf->b_p_lisp) {
    SET_CHARTAB(buf, '-');
  }

  // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
  // options Each option is a list of characters, character numbers or
  // ranges, separated by commas, e.g.: "200-210,x,#-178,-"
  for (i = global ? 0 : 3; i <= 3; ++i) {
    if (i == 0) {
      // first round: 'isident'
      p = p_isi;
    } else if (i == 1) {
      // second round: 'isprint'
      p = p_isp;
    } else if (i == 2) {
      // third round: 'isfname'
      p = p_isf;
    } else {  // i == 3
      // fourth round: 'iskeyword'
      p = buf->b_p_isk;
    }

    while (*p) {
      tilde = FALSE;
      do_isalpha = FALSE;

      if ((*p == '^') && (p[1] != NUL)) {
        tilde = TRUE;
        ++p;
      }

      if (VIM_ISDIGIT(*p)) {
        c = getdigits(&p);
      } else if (has_mbyte) {
        c = mb_ptr2char_adv(&p);
      } else {
        c = *p++;
      }
      c2 = -1;

      if ((*p == '-') && (p[1] != NUL)) {
        ++p;

        if (VIM_ISDIGIT(*p)) {
          c2 = getdigits(&p);
        } else if (has_mbyte) {
          c2 = mb_ptr2char_adv(&p);
        } else {
          c2 = *p++;
        }
      }

      if ((c <= 0)
          || (c >= 256)
          || ((c2 < c) && (c2 != -1))
          || (c2 >= 256)
          || !((*p == NUL) || (*p == ','))) {
        return FAIL;
      }

      if (c2 == -1) {  // not a range
        // A single '@' (not "@-@"):
        // Decide on letters being ID/printable/keyword chars with
        // standard function isalpha(). This takes care of locale for
        // single-byte characters).
        if (c == '@') {
          do_isalpha = TRUE;
          c = 1;
          c2 = 255;
        } else {
          c2 = c;
        }
      }

      while (c <= c2) {
        // Use the MB_ functions here, because isalpha() doesn't
        // work properly when 'encoding' is "latin1" and the locale is
        // "C".
        if (!do_isalpha
            || MB_ISLOWER(c)
            || MB_ISUPPER(c)
            || (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))) {
          if (i == 0) {
            // (re)set ID flag
            if (tilde) {
              chartab[c] &= ~CT_ID_CHAR;
            } else {
              chartab[c] |= CT_ID_CHAR;
            }
          } else if (i == 1) {
            // (re)set printable
            // For double-byte we keep the cell width, so
            // that we can detect it from the first byte.
            if (((c < ' ')
                 || (c > '~')
                 || (p_altkeymap && (F_isalpha(c) || F_isdigit(c))))
                && !(enc_dbcs && (MB_BYTE2LEN(c) == 2))) {
              if (tilde) {
                chartab[c] = (chartab[c] & ~CT_CELL_MASK)
                             + ((dy_flags & DY_UHEX) ? 4 : 2);
                chartab[c] &= ~CT_PRINT_CHAR;
              } else {
                chartab[c] = (chartab[c] & ~CT_CELL_MASK) + 1;
                chartab[c] |= CT_PRINT_CHAR;
              }
            }
          } else if (i == 2) {
            // (re)set fname flag
            if (tilde) {
              chartab[c] &= ~CT_FNAME_CHAR;
            } else {
              chartab[c] |= CT_FNAME_CHAR;
            }
          } else {  // i == 3
            // (re)set keyword flag
            if (tilde) {
              RESET_CHARTAB(buf, c);
            } else {
              SET_CHARTAB(buf, c);
            }
          }
        }
        ++c;
      }

      c = *p;
      p = skip_to_option_part(p);

      if ((c == ',') && (*p == NUL)) {
        // Trailing comma is not allowed.
        return FAIL;
      }
    }
  }
  chartab_initialized = TRUE;
  return OK;
}
Esempio n. 8
0
int 
buf_init_chartab (
    buf_T *buf,
    int global                     /* FALSE: only set buf->b_chartab[] */
)
{
  int c;
  int c2;
  char_u      *p;
  int i;
  int tilde;
  int do_isalpha;

  if (global) {
    /*
     * Set the default size for printable characters:
     * From <Space> to '~' is 1 (printable), others are 2 (not printable).
     * This also inits all 'isident' and 'isfname' flags to FALSE.
     *
     * EBCDIC: all chars below ' ' are not printable, all others are
     * printable.
     */
    c = 0;
    while (c < ' ')
      chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
    while (c <= '~')
      chartab[c++] = 1 + CT_PRINT_CHAR;
    if (p_altkeymap) {
      while (c < YE)
        chartab[c++] = 1 + CT_PRINT_CHAR;
    }
    while (c < 256) {
      /* UTF-8: bytes 0xa0 - 0xff are printable (latin1) */
      if (enc_utf8 && c >= 0xa0)
        chartab[c++] = CT_PRINT_CHAR + 1;
      /* euc-jp characters starting with 0x8e are single width */
      else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
        chartab[c++] = CT_PRINT_CHAR + 1;
      /* other double-byte chars can be printable AND double-width */
      else if (enc_dbcs != 0 && MB_BYTE2LEN(c) == 2)
        chartab[c++] = CT_PRINT_CHAR + 2;
      else
        /* the rest is unprintable by default */
        chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
    }

    /* Assume that every multi-byte char is a filename character. */
    for (c = 1; c < 256; ++c)
      if ((enc_dbcs != 0 && MB_BYTE2LEN(c) > 1)
          || (enc_dbcs == DBCS_JPNU && c == 0x8e)
          || (enc_utf8 && c >= 0xa0))
        chartab[c] |= CT_FNAME_CHAR;
  }

  /*
   * Init word char flags all to FALSE
   */
  vim_memset(buf->b_chartab, 0, (size_t)32);
  if (enc_dbcs != 0)
    for (c = 0; c < 256; ++c) {
      /* double-byte characters are probably word characters */
      if (MB_BYTE2LEN(c) == 2)
        SET_CHARTAB(buf, c);
    }

  /*
   * In lisp mode the '-' character is included in keywords.
   */
  if (buf->b_p_lisp)
    SET_CHARTAB(buf, '-');

  /* Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
   * options Each option is a list of characters, character numbers or
   * ranges, separated by commas, e.g.: "200-210,x,#-178,-"
   */
  for (i = global ? 0 : 3; i <= 3; ++i) {
    if (i == 0)
      p = p_isi;                /* first round: 'isident' */
    else if (i == 1)
      p = p_isp;                /* second round: 'isprint' */
    else if (i == 2)
      p = p_isf;                /* third round: 'isfname' */
    else        /* i == 3 */
      p = buf->b_p_isk;         /* fourth round: 'iskeyword' */

    while (*p) {
      tilde = FALSE;
      do_isalpha = FALSE;
      if (*p == '^' && p[1] != NUL) {
        tilde = TRUE;
        ++p;
      }
      if (VIM_ISDIGIT(*p))
        c = getdigits(&p);
      else if (has_mbyte)
        c = mb_ptr2char_adv(&p);
      else
        c = *p++;
      c2 = -1;
      if (*p == '-' && p[1] != NUL) {
        ++p;
        if (VIM_ISDIGIT(*p))
          c2 = getdigits(&p);
        else if (has_mbyte)
          c2 = mb_ptr2char_adv(&p);
        else
          c2 = *p++;
      }
      if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256
          || !(*p == NUL || *p == ','))
        return FAIL;

      if (c2 == -1) {           /* not a range */
        /*
         * A single '@' (not "@-@"):
         * Decide on letters being ID/printable/keyword chars with
         * standard function isalpha(). This takes care of locale for
         * single-byte characters).
         */
        if (c == '@') {
          do_isalpha = TRUE;
          c = 1;
          c2 = 255;
        } else
          c2 = c;
      }
      while (c <= c2) {
        /* Use the MB_ functions here, because isalpha() doesn't
         * work properly when 'encoding' is "latin1" and the locale is
         * "C".  */
        if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)
            || (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))
            ) {
          if (i == 0) {                         /* (re)set ID flag */
            if (tilde)
              chartab[c] &= ~CT_ID_CHAR;
            else
              chartab[c] |= CT_ID_CHAR;
          } else if (i == 1)   {                /* (re)set printable */
            if ((c < ' '
                 || c > '~'
                 || (p_altkeymap
                     && (F_isalpha(c) || F_isdigit(c)))
                 )
                /* For double-byte we keep the cell width, so
                 * that we can detect it from the first byte. */
                && !(enc_dbcs && MB_BYTE2LEN(c) == 2)
                ) {
              if (tilde) {
                chartab[c] = (chartab[c] & ~CT_CELL_MASK)
                             + ((dy_flags & DY_UHEX) ? 4 : 2);
                chartab[c] &= ~CT_PRINT_CHAR;
              } else   {
                chartab[c] = (chartab[c] & ~CT_CELL_MASK) + 1;
                chartab[c] |= CT_PRINT_CHAR;
              }
            }
          } else if (i == 2)   {                /* (re)set fname flag */
            if (tilde)
              chartab[c] &= ~CT_FNAME_CHAR;
            else
              chartab[c] |= CT_FNAME_CHAR;
          } else   {     /* i == 3 */		/* (re)set keyword flag */
            if (tilde)
              RESET_CHARTAB(buf, c);
            else
              SET_CHARTAB(buf, c);
          }
        }
        ++c;
      }

      c = *p;
      p = skip_to_option_part(p);
      if (c == ',' && *p == NUL)
        /* Trailing comma is not allowed. */
        return FAIL;
    }
  }
  chartab_initialized = TRUE;
  return OK;
}
Esempio n. 9
0
/// Map Farsi keyboard when in fkmap mode.
int fkmap(int c)
{
  int tempc;
  static int revins;

  if (IS_SPECIAL(c)) {
    return c;
  }

  if (VIM_ISDIGIT(c)
      || (((c == '.')
           || (c == '+')
           || (c == '-')
           || (c == '^')
           || (c == '%')
           || (c == '#')
           || (c == '='))
          && revins)) {
    if (!revins) {
      if (curwin->w_cursor.col) {
        if (!p_ri) {
          dec_cursor();
        }

        chg_c_toX_orX();
        chg_l_toXor_X();
        if (!p_ri) {
          inc_cursor();
        }
      }
    }

    arrow_used = TRUE;
    (void)stop_arrow();

    if (!curwin->w_p_rl && revins) {
      inc_cursor();
    }

    revins++;
    p_ri = 1;
  } else {
    if (revins) {
      arrow_used = TRUE;
      (void)stop_arrow();

      revins = 0;
      if (curwin->w_p_rl) {
        while ((F_isdigit(gchar_cursor())
                || (gchar_cursor() == F_PERIOD
                    || gchar_cursor() == F_PLUS
                    || gchar_cursor() == F_MINUS
                    || gchar_cursor() == F_MUL
                    || gchar_cursor() == F_DIVIDE
                    || gchar_cursor() == F_PERCENT
                    || gchar_cursor() == F_EQUALS))
                && gchar_cursor() != '\0') {
          curwin->w_cursor.col++;
        }
      } else {
        if (curwin->w_cursor.col) {
          while ((F_isdigit(gchar_cursor())
                 || (gchar_cursor() == F_PERIOD
                     || gchar_cursor() == F_PLUS
                     || gchar_cursor() == F_MINUS
                     || gchar_cursor() == F_MUL
                     || gchar_cursor() == F_DIVIDE
                     || gchar_cursor() == F_PERCENT
                     || gchar_cursor() == F_EQUALS))
                 && --curwin->w_cursor.col) {
          }
        }

        if (!F_isdigit(gchar_cursor())) {
          ++curwin->w_cursor.col;
        }
      }
    }
  }

  if (!revins) {
    if (curwin->w_p_rl) {
      p_ri = 0;
    }

    if (!curwin->w_p_rl) {
      p_ri = 1;
    }
  }

  if ((c < 0x100) &&
      (isalpha(c) ||
       (c == '&') ||
       (c == '^') ||
       (c == ';') ||
       (c == '\'') ||
       (c == ',') ||
       (c == '[') ||
       (c == ']') ||
       (c == '{') ||
       (c == '}'))) {
    chg_r_to_Xor_X_();
  }

  tempc = 0;
  switch (c) {
    case '`':
    case ' ':
    case '.':
    case '!':
    case '"':
    case '$':
    case '%':
    case '^':
    case '&':
    case '/':
    case '(':
    case ')':
    case '=':
    case '\\':
    case '?':
    case '+':
    case '-':
    case '_':
    case '*':
    case ':':
    case '#':
    case '~':
    case '@':
    case '<':
    case '>':
    case '{':
    case '}':
    case '|':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case 'B':
    case 'E':
    case 'F':
    case 'H':
    case 'I':
    case 'K':
    case 'L':
    case 'M':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'T':
    case 'U':
    case 'W':
    case 'Y':
    case  NL:
    case  TAB:
      if (p_ri && (c == NL) && curwin->w_cursor.col) {
        // If the char before the cursor is _X_ or X_ do not change
        // the one under the cursor with X type.

        dec_cursor();
        if (F_isalpha(gchar_cursor())) {
          inc_cursor();
          return NL;
        }
        inc_cursor();
      }

      if (!p_ri) {
        if (!curwin->w_cursor.col) {
          switch (c) {
            case '0':
              return FARSI_0;

            case '1':
              return FARSI_1;

            case '2':
              return FARSI_2;

            case '3':
              return FARSI_3;

            case '4':
              return FARSI_4;

            case '5':
              return FARSI_5;

            case '6':
              return FARSI_6;

            case '7':
              return FARSI_7;

            case '8':
              return FARSI_8;

            case '9':
              return FARSI_9;

            case 'B':
              return F_PSP;

            case 'E':
              return JAZR_N;

            case 'F':
              return ALEF_D_H;

            case 'H':
              return ALEF_A;

            case 'I':
              return TASH;

            case 'K':
              return F_LQUOT;

            case 'L':
              return F_RQUOT;

            case 'M':
              return HAMZE;

            case 'O':
              return '[';

            case 'P':
              return ']';

            case 'Q':
              return OO;

            case 'R':
              return MAD_N;

            case 'T':
              return OW;

            case 'U':
              return MAD;

            case 'W':
              return OW_OW;

            case 'Y':
              return JAZR;

            case '`':
              return F_PCN;

            case '!':
              return F_EXCL;

            case '@':
              return F_COMMA;

            case '#':
              return F_DIVIDE;

            case '$':
              return F_CURRENCY;

            case '%':
              return F_PERCENT;

            case '^':
              return F_MUL;

            case '&':
              return F_BCOMMA;

            case '*':
              return F_STAR;

            case '(':
              return F_LPARENT;

            case ')':
              return F_RPARENT;

            case '-':
              return F_MINUS;

            case '_':
              return F_UNDERLINE;

            case '=':
              return F_EQUALS;

            case '+':
              return F_PLUS;

            case '\\':
              return F_BSLASH;

            case '|':
              return F_PIPE;

            case ':':
              return F_DCOLON;

            case '"':
              return F_SEMICOLON;

            case '.':
              return F_PERIOD;

            case '/':
              return F_SLASH;

            case '<':
              return F_LESS;

            case '>':
              return F_GREATER;

            case '?':
              return F_QUESTION;

            case ' ':
              return F_BLANK;
          }
          break;
        }
      }

      if (!p_ri) {
        dec_cursor();
      }

      switch ((tempc = gchar_cursor())) {
        case _BE:
        case _PE:
        case _TE:
        case _SE:
        case _JIM:
        case _CHE:
        case _HE_J:
        case _XE:
        case _SIN:
        case _SHIN:
        case _SAD:
        case _ZAD:
        case _FE:
        case _GHAF:
        case _KAF:
        case _KAF_H:
        case _GAF:
        case _LAM:
        case _MIM:
        case _NOON:
        case _HE:
        case _HE_:
        case _TA:
        case _ZA:
          put_curr_and_l_to_X(toF_TyA(tempc));
          break;

        case _AYN:
        case _AYN_:
          if (!p_ri) {
            if (!curwin->w_cursor.col) {
              put_curr_and_l_to_X(AYN);
              break;
            }
          }

          if (p_ri) {
            inc_cursor();
          } else {
            dec_cursor();
          }

          if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
            tempc = AYN_;
          } else {
            tempc = AYN;
          }

          if (p_ri) {
            dec_cursor();
          } else {
            inc_cursor();
          }

          put_curr_and_l_to_X(tempc);
          break;

        case _GHAYN:
        case _GHAYN_:

          if (!p_ri) {
            if (!curwin->w_cursor.col) {
              put_curr_and_l_to_X(GHAYN);
              break;
            }
          }

          if (p_ri) {
            inc_cursor();
          } else {
            dec_cursor();
          }

          if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
            tempc = GHAYN_;
          } else {
            tempc = GHAYN;
          }

          if (p_ri) {
            dec_cursor();
          } else {
            inc_cursor();
          }

          put_curr_and_l_to_X(tempc);
          break;

        case _YE:
        case _IE:
        case _YEE:

          if (!p_ri) {
            if (!curwin->w_cursor.col) {
              put_curr_and_l_to_X((tempc == _YE ? YE :
                                   (tempc == _IE ? IE : YEE)));
              break;
            }
          }

          if (p_ri) {
            inc_cursor();
          } else {
            dec_cursor();
          }

          if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
            tempc = (tempc == _YE ? YE_ :
                     (tempc == _IE ? IE_ : YEE_));
          } else {
            tempc = (tempc == _YE ? YE :
                     (tempc == _IE ? IE : YEE));
          }

          if (p_ri) {
            dec_cursor();
          } else {
            inc_cursor();
          }

          put_curr_and_l_to_X(tempc);
          break;
      }

      if (!p_ri) {
        inc_cursor();
      }

      tempc = 0;

      switch (c) {
        case '0':
          return FARSI_0;

        case '1':
          return FARSI_1;

        case '2':
          return FARSI_2;

        case '3':
          return FARSI_3;

        case '4':
          return FARSI_4;

        case '5':
          return FARSI_5;

        case '6':
          return FARSI_6;

        case '7':
          return FARSI_7;

        case '8':
          return FARSI_8;

        case '9':
          return FARSI_9;

        case 'B':
          return F_PSP;

        case 'E':
          return JAZR_N;

        case 'F':
          return ALEF_D_H;

        case 'H':
          return ALEF_A;

        case 'I':
          return TASH;

        case 'K':
          return F_LQUOT;

        case 'L':
          return F_RQUOT;

        case 'M':
          return HAMZE;

        case 'O':
          return '[';

        case 'P':
          return ']';

        case 'Q':
          return OO;

        case 'R':
          return MAD_N;

        case 'T':
          return OW;

        case 'U':
          return MAD;

        case 'W':
          return OW_OW;

        case 'Y':
          return JAZR;

        case '`':
          return F_PCN;

        case '!':
          return F_EXCL;

        case '@':
          return F_COMMA;

        case '#':
          return F_DIVIDE;

        case '$':
          return F_CURRENCY;

        case '%':
          return F_PERCENT;

        case '^':
          return F_MUL;

        case '&':
          return F_BCOMMA;

        case '*':
          return F_STAR;

        case '(':
          return F_LPARENT;

        case ')':
          return F_RPARENT;

        case '-':
          return F_MINUS;

        case '_':
          return F_UNDERLINE;

        case '=':
          return F_EQUALS;

        case '+':
          return F_PLUS;

        case '\\':
          return F_BSLASH;

        case '|':
          return F_PIPE;

        case ':':
          return F_DCOLON;

        case '"':
          return F_SEMICOLON;

        case '.':
          return F_PERIOD;

        case '/':
          return F_SLASH;

        case '<':
          return F_LESS;

        case '>':
          return F_GREATER;

        case '?':
          return F_QUESTION;

        case ' ':
          return F_BLANK;
      }
      break;

    case 'a':
      tempc = _SHIN;
      break;

    case 'A':
      tempc = WAW_H;
      break;

    case 'b':
      tempc = ZAL;
      break;

    case 'c':
      tempc = ZE;
      break;

    case 'C':
      tempc = JE;
      break;

    case 'd':
      tempc = _YE;
      break;

    case 'D':
      tempc = _YEE;
      break;

    case 'e':
      tempc = _SE;
      break;

    case 'f':
      tempc = _BE;
      break;

    case 'g':
      tempc = _LAM;
      break;

    case 'G':
      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (gchar_cursor() == _LAM) {
          chg_c_toX_orX();
        } else if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri) {
        if (!curwin->w_cursor.col) {
          return ALEF_U_H;
        }
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (gchar_cursor() == _LAM) {
        chg_c_toX_orX();
        chg_l_toXor_X();
        tempc = ALEF_U_H;
      } else if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
        tempc = ALEF_U_H_;
        chg_l_toXor_X();
      } else {
        tempc = ALEF_U_H;
      }

      if (!p_ri) {
        inc_cursor();
      }

      return tempc;

    case 'h':
      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri) {
        if (!curwin->w_cursor.col) {
          return ALEF;
        }
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (gchar_cursor() == _LAM) {
        chg_l_toXor_X();
        del_char(FALSE);
        AppendCharToRedobuff(K_BS);

        if (!p_ri) {
          dec_cursor();
        }

        tempc = LA;
      } else {
        if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
          tempc = ALEF_;
          chg_l_toXor_X();
        } else {
          tempc = ALEF;
        }
      }

      if (!p_ri) {
        inc_cursor();
      }

      return tempc;

    case 'i':

      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (!p_ri && !F_is_TyE(tempc)) {
          chg_c_to_X_orX_();
        }

        if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri && !curwin->w_cursor.col) {
        return _HE;
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
        tempc = _HE_;
      } else {
        tempc = _HE;
      }

      if (!p_ri) {
        inc_cursor();
      }
      break;

    case 'j':
      tempc = _TE;
      break;

    case 'J':

      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri) {
        if (!curwin->w_cursor.col) {
          return TEE;
        }
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
        tempc = TEE_;
        chg_l_toXor_X();
      } else {
        tempc = TEE;
      }

      if (!p_ri) {
        inc_cursor();
      }

      return tempc;

    case 'k':
      tempc = _NOON;
      break;

    case 'l':
      tempc = _MIM;
      break;

    case 'm':
      tempc = _PE;
      break;

    case 'n':
    case 'N':
      tempc = DAL;
      break;

    case 'o':
      tempc = _XE;
      break;

    case 'p':
      tempc = _HE_J;
      break;

    case 'q':
      tempc = _ZAD;
      break;

    case 'r':
      tempc = _GHAF;
      break;

    case 's':
      tempc = _SIN;
      break;

    case 'S':
      tempc = _IE;
      break;

    case 't':
      tempc = _FE;
      break;

    case 'u':
      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (!p_ri && !F_is_TyE(tempc)) {
          chg_c_to_X_orX_();
        }

        if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri && !curwin->w_cursor.col) {
        return _AYN;
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
        tempc = _AYN_;
      } else {
        tempc = _AYN;
      }

      if (!p_ri) {
        inc_cursor();
      }
      break;

    case 'v':
    case 'V':
      tempc = RE;
      break;

    case 'w':
      tempc = _SAD;
      break;

    case 'x':
    case 'X':
      tempc = _TA;
      break;

    case 'y':
      if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
        if (!p_ri && !F_is_TyE(tempc)) {
          chg_c_to_X_orX_();
        }

        if (p_ri) {
          chg_c_to_X_or_X();
        }
      }

      if (!p_ri && !curwin->w_cursor.col) {
        return _GHAYN;
      }

      if (!p_ri) {
        dec_cursor();
      }

      if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
        tempc = _GHAYN_;
      } else {
        tempc = _GHAYN;
      }

      if (!p_ri) {
        inc_cursor();
      }

      break;

    case 'z':
      tempc = _ZA;
      break;

    case 'Z':
      tempc = _KAF_H;
      break;

    case ';':
      tempc = _KAF;
      break;

    case '\'':
      tempc = _GAF;
      break;

    case ',':
      tempc = WAW;
      break;

    case '[':
      tempc = _JIM;
      break;

    case ']':
      tempc = _CHE;
      break;
  }

  if ((F_isalpha(tempc) || F_isdigit(tempc))) {
    if (!curwin->w_cursor.col && STRLEN(ml_get_curline())) {
      if (!p_ri && !F_is_TyE(tempc)) {
        chg_c_to_X_orX_();
      }

      if (p_ri) {
        chg_c_to_X_or_X();
      }
    }

    if (curwin->w_cursor.col) {
      if (!p_ri) {
        dec_cursor();
      }

      if (F_is_TyE(tempc)) {
        chg_l_toXor_X();
      } else {
        chg_l_to_X_orX_();
      }

      if (!p_ri) {
        inc_cursor();
      }
    }
  }

  if (tempc) {
    return tempc;
  }
  return c;
}
Esempio n. 10
0
/*
 * ":delmarks[!] [marks]"
 */
void ex_delmarks(exarg_T *eap)
{
  char_u      *p;
  int from, to;
  int i;
  int lower;
  int digit;
  int n;

  if (*eap->arg == NUL && eap->forceit)
    /* clear all marks */
    clrallmarks(curbuf);
  else if (eap->forceit)
    EMSG(_(e_invarg));
  else if (*eap->arg == NUL)
    EMSG(_(e_argreq));
  else {
    /* clear specified marks only */
    for (p = eap->arg; *p != NUL; ++p) {
      lower = ASCII_ISLOWER(*p);
      digit = VIM_ISDIGIT(*p);
      if (lower || digit || ASCII_ISUPPER(*p)) {
        if (p[1] == '-') {
          /* clear range of marks */
          from = *p;
          to = p[2];
          if (!(lower ? ASCII_ISLOWER(p[2])
                : (digit ? VIM_ISDIGIT(p[2])
                   : ASCII_ISUPPER(p[2])))
              || to < from) {
            EMSG2(_(e_invarg2), p);
            return;
          }
          p += 2;
        } else
          /* clear one lower case mark */
          from = to = *p;

        for (i = from; i <= to; ++i) {
          if (lower)
            curbuf->b_namedm[i - 'a'].lnum = 0;
          else {
            if (digit)
              n = i - '0' + NMARKS;
            else
              n = i - 'A';
            namedfm[n].fmark.mark.lnum = 0;
            vim_free(namedfm[n].fname);
            namedfm[n].fname = NULL;
          }
        }
      } else
        switch (*p) {
        case '"': curbuf->b_last_cursor.lnum = 0; break;
        case '^': curbuf->b_last_insert.lnum = 0; break;
        case '.': curbuf->b_last_change.lnum = 0; break;
        case '[': curbuf->b_op_start.lnum    = 0; break;
        case ']': curbuf->b_op_end.lnum      = 0; break;
        case '<': curbuf->b_visual.vi_start.lnum = 0; break;
        case '>': curbuf->b_visual.vi_end.lnum   = 0; break;
        case ' ': break;
        default:  EMSG2(_(e_invarg2), p);
          return;
        }
    }
  }
}
Esempio n. 11
0
pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum)
{
  pos_T               *posp;
  pos_T               *startp, *endp;
  static pos_T pos_copy;

  posp = NULL;

  /* Check for special key, can't be a mark name and might cause islower()
   * to crash. */
  if (c < 0)
    return posp;
  if (c > '~')                          /* check for islower()/isupper() */
    ;
  else if (c == '\'' || c == '`')  {    /* previous context mark */
    pos_copy = curwin->w_pcmark;        /* need to make a copy because */
    posp = &pos_copy;                   /*   w_pcmark may be changed soon */
  } else if (c == '"')                  /* to pos when leaving buffer */
    posp = &(buf->b_last_cursor);
  else if (c == '^')                    /* to where Insert mode stopped */
    posp = &(buf->b_last_insert);
  else if (c == '.')                    /* to where last change was made */
    posp = &(buf->b_last_change);
  else if (c == '[')                    /* to start of previous operator */
    posp = &(buf->b_op_start);
  else if (c == ']')                    /* to end of previous operator */
    posp = &(buf->b_op_end);
  else if (c == '{' || c == '}') {      /* to previous/next paragraph */
    pos_T pos;
    oparg_T oa;
    int slcb = listcmd_busy;

    pos = curwin->w_cursor;
    listcmd_busy = TRUE;            /* avoid that '' is changed */
    if (findpar(&oa.inclusive,
            c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE)) {
      pos_copy = curwin->w_cursor;
      posp = &pos_copy;
    }
    curwin->w_cursor = pos;
    listcmd_busy = slcb;
  } else if (c == '(' || c == ')')   {  /* to previous/next sentence */
    pos_T pos;
    int slcb = listcmd_busy;

    pos = curwin->w_cursor;
    listcmd_busy = TRUE;            /* avoid that '' is changed */
    if (findsent(c == ')' ? FORWARD : BACKWARD, 1L)) {
      pos_copy = curwin->w_cursor;
      posp = &pos_copy;
    }
    curwin->w_cursor = pos;
    listcmd_busy = slcb;
  } else if (c == '<' || c == '>')   {  /* start/end of visual area */
    startp = &buf->b_visual.vi_start;
    endp = &buf->b_visual.vi_end;
    if ((c == '<') == lt(*startp, *endp))
      posp = startp;
    else
      posp = endp;
    /*
     * For Visual line mode, set mark at begin or end of line
     */
    if (buf->b_visual.vi_mode == 'V') {
      pos_copy = *posp;
      posp = &pos_copy;
      if (c == '<')
        pos_copy.col = 0;
      else
        pos_copy.col = MAXCOL;
      pos_copy.coladd = 0;
    }
  } else if (ASCII_ISLOWER(c))   {      /* normal named mark */
    posp = &(buf->b_namedm[c - 'a']);
  } else if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c))   {    /* named file mark */
    if (VIM_ISDIGIT(c))
      c = c - '0' + NMARKS;
    else
      c -= 'A';
    posp = &(namedfm[c].fmark.mark);

    if (namedfm[c].fmark.fnum == 0)
      fname2fnum(&namedfm[c]);

    if (fnum != NULL)
      *fnum = namedfm[c].fmark.fnum;
    else if (namedfm[c].fmark.fnum != buf->b_fnum) {
      /* mark is in another file */
      posp = &pos_copy;

      if (namedfm[c].fmark.mark.lnum != 0
          && changefile && namedfm[c].fmark.fnum) {
        if (buflist_getfile(namedfm[c].fmark.fnum,
                (linenr_T)1, GETF_SETMARK, FALSE) == OK) {
          /* Set the lnum now, autocommands could have changed it */
          curwin->w_cursor = namedfm[c].fmark.mark;
          return (pos_T *)-1;
        }
        pos_copy.lnum = -1;             /* can't get file */
      } else
        pos_copy.lnum = 0;              /* mark exists, but is not valid in
                                           current buffer */
    }
  }

  return posp;
}
Esempio n. 12
0
File: json.c Progetto: Qubit0-1/vim
/*
 * Decode one item and put it in "res".  If "res" is NULL only advance.
 * Must already have skipped white space.
 *
 * Return FAIL for a decoding error.
 * Return MAYBE for an incomplete message.
 */
    static int
json_decode_item(js_read_T *reader, typval_T *res, int options)
{
    char_u	*p;
    int		len;

    fill_numbuflen(reader);
    p = reader->js_buf + reader->js_used;
    switch (*p)
    {
	case '[': /* array */
	    return json_decode_array(reader, res, options);

	case '{': /* object */
	    return json_decode_object(reader, res, options);

	case '"': /* string */
	    return json_decode_string(reader, res);

	case ',': /* comma: empty item */
	    if ((options & JSON_JS) == 0)
		return FAIL;
	    /* FALLTHROUGH */
	case NUL: /* empty */
	    if (res != NULL)
	    {
		res->v_type = VAR_SPECIAL;
		res->vval.v_number = VVAL_NONE;
	    }
	    return OK;

	default:
	    if (VIM_ISDIGIT(*p) || *p == '-')
	    {
		char_u  *sp = p;

#ifdef FEAT_FLOAT
		if (*sp == '-')
		{
		    ++sp;
		    if (*sp == NUL)
			return MAYBE;
		    if (!VIM_ISDIGIT(*sp))
			return FAIL;
		}
		sp = skipdigits(sp);
		if (*sp == '.' || *sp == 'e' || *sp == 'E')
		{
		    if (res == NULL)
		    {
			float_T f;

			len = string2float(p, &f);
		    }
		    else
		    {
			res->v_type = VAR_FLOAT;
			len = string2float(p, &res->vval.v_float);
		    }
		}
		else
#endif
		{
		    long nr;

		    vim_str2nr(reader->js_buf + reader->js_used,
			    NULL, &len, 0, /* what */
			    &nr, NULL, 0);
		    if (res != NULL)
		    {
			res->v_type = VAR_NUMBER;
			res->vval.v_number = nr;
		    }
		}
		reader->js_used += len;
		return OK;
	    }
	    if (STRNICMP((char *)p, "false", 5) == 0)
	    {
		reader->js_used += 5;
		if (res != NULL)
		{
		    res->v_type = VAR_SPECIAL;
		    res->vval.v_number = VVAL_FALSE;
		}
		return OK;
	    }
	    if (STRNICMP((char *)p, "true", 4) == 0)
	    {
		reader->js_used += 4;
		if (res != NULL)
		{
		    res->v_type = VAR_SPECIAL;
		    res->vval.v_number = VVAL_TRUE;
		}
		return OK;
	    }
	    if (STRNICMP((char *)p, "null", 4) == 0)
	    {
		reader->js_used += 4;
		if (res != NULL)
		{
		    res->v_type = VAR_SPECIAL;
		    res->vval.v_number = VVAL_NULL;
		}
		return OK;
	    }
	    /* check for truncated name */
	    len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
	    if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
		    || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
			       ||  STRNICMP((char *)p, "null", len) == 0)))
		return MAYBE;
	    break;
    }

    if (res != NUL)
    {
	res->v_type = VAR_SPECIAL;
	res->vval.v_number = VVAL_NONE;
    }
    return FAIL;
}
Esempio n. 13
0
/*
 * Work out what to complete when doing command line completion of menu names.
 */
char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit)
{
  char_u      *after_dot;
  char_u      *p;
  char_u      *path_name = NULL;
  char_u      *name;
  int unmenu;
  vimmenu_T   *menu;
  int expand_menus;

  xp->xp_context = EXPAND_UNSUCCESSFUL;


  /* Check for priority numbers, enable and disable */
  for (p = arg; *p; ++p)
    if (!VIM_ISDIGIT(*p) && *p != '.')
      break;

  if (!vim_iswhite(*p)) {
    if (STRNCMP(arg, "enable", 6) == 0
        && (arg[6] == NUL ||  vim_iswhite(arg[6])))
      p = arg + 6;
    else if (STRNCMP(arg, "disable", 7) == 0
             && (arg[7] == NUL || vim_iswhite(arg[7])))
      p = arg + 7;
    else
      p = arg;
  }

  while (*p != NUL && vim_iswhite(*p))
    ++p;

  arg = after_dot = p;

  for (; *p && !vim_iswhite(*p); ++p) {
    if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
      p++;
    else if (*p == '.')
      after_dot = p + 1;
  }

  /* ":tearoff" and ":popup" only use menus, not entries */
  expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
  expand_emenu = (*cmd == 'e');
  if (expand_menus && vim_iswhite(*p))
    return NULL;        /* TODO: check for next command? */
  if (*p == NUL) {              /* Complete the menu name */
    /*
     * With :unmenu, you only want to match menus for the appropriate mode.
     * With :menu though you might want to add a menu with the same name as
     * one in another mode, so match menus from other modes too.
     */
    expand_modes = get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
    if (!unmenu)
      expand_modes = MENU_ALL_MODES;

    menu = root_menu;
    if (after_dot != arg) {
      path_name = xmalloc(after_dot - arg);
      STRLCPY(path_name, arg, after_dot - arg);
    }
    name = path_name;
    while (name != NULL && *name) {
      p = menu_name_skip(name);
      while (menu != NULL) {
        if (menu_name_equal(name, menu)) {
          /* Found menu */
          if ((*p != NUL && menu->children == NULL)
              || ((menu->modes & expand_modes) == 0x0)) {
            /*
             * Menu path continues, but we have reached a leaf.
             * Or menu exists only in another mode.
             */
            free(path_name);
            return NULL;
          }
          break;
        }
        menu = menu->next;
      }
      if (menu == NULL) {
        /* No menu found with the name we were looking for */
        free(path_name);
        return NULL;
      }
      name = p;
      menu = menu->children;
    }
    free(path_name);

    xp->xp_context = expand_menus ? EXPAND_MENUNAMES : EXPAND_MENUS;
    xp->xp_pattern = after_dot;
    expand_menu = menu;
  } else                        /* We're in the mapping part */
    xp->xp_context = EXPAND_NOTHING;
  return NULL;
}
Esempio n. 14
0
/*
 * Do the :menu command and relatives.
 */
void 
ex_menu (
    exarg_T *eap                   /* Ex command arguments */
)
{
  char_u      *menu_path;
  int modes;
  char_u      *map_to;
  int noremap;
  int silent = FALSE;
  int special = FALSE;
  int unmenu;
  char_u      *map_buf;
  char_u      *arg;
  char_u      *p;
  int i;
  int pri_tab[MENUDEPTH + 1];
  int enable = MAYBE;               /* TRUE for "menu enable", FALSE for "menu
                                     * disable */
  vimmenu_T menuarg;

  modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
  arg = eap->arg;

  for (;; ) {
    if (STRNCMP(arg, "<script>", 8) == 0) {
      noremap = REMAP_SCRIPT;
      arg = skipwhite(arg + 8);
      continue;
    }
    if (STRNCMP(arg, "<silent>", 8) == 0) {
      silent = TRUE;
      arg = skipwhite(arg + 8);
      continue;
    }
    if (STRNCMP(arg, "<special>", 9) == 0) {
      special = TRUE;
      arg = skipwhite(arg + 9);
      continue;
    }
    break;
  }


  /* Locate an optional "icon=filename" argument. */
  if (STRNCMP(arg, "icon=", 5) == 0) {
    arg += 5;
    while (*arg != NUL && *arg != ' ') {
      if (*arg == '\\')
        STRMOVE(arg, arg + 1);
      mb_ptr_adv(arg);
    }
    if (*arg != NUL) {
      *arg++ = NUL;
      arg = skipwhite(arg);
    }
  }

  /*
   * Fill in the priority table.
   */
  for (p = arg; *p; ++p)
    if (!VIM_ISDIGIT(*p) && *p != '.')
      break;
  if (vim_iswhite(*p)) {
    for (i = 0; i < MENUDEPTH && !vim_iswhite(*arg); ++i) {
      pri_tab[i] = getdigits_int(&arg);
      if (pri_tab[i] == 0)
        pri_tab[i] = 500;
      if (*arg == '.')
        ++arg;
    }
    arg = skipwhite(arg);
  } else if (eap->addr_count && eap->line2 != 0) {
    pri_tab[0] = eap->line2;
    i = 1;
  } else
    i = 0;
  while (i < MENUDEPTH)
    pri_tab[i++] = 500;
  pri_tab[MENUDEPTH] = -1;              /* mark end of the table */

  /*
   * Check for "disable" or "enable" argument.
   */
  if (STRNCMP(arg, "enable", 6) == 0 && vim_iswhite(arg[6])) {
    enable = TRUE;
    arg = skipwhite(arg + 6);
  } else if (STRNCMP(arg, "disable", 7) == 0 && vim_iswhite(arg[7])) {
    enable = FALSE;
    arg = skipwhite(arg + 7);
  }

  /*
   * If there is no argument, display all menus.
   */
  if (*arg == NUL) {
    show_menus(arg, modes);
    return;
  }


  menu_path = arg;
  if (*menu_path == '.') {
    EMSG2(_(e_invarg2), menu_path);
    goto theend;
  }

  map_to = menu_translate_tab_and_shift(arg);

  /*
   * If there is only a menu name, display menus with that name.
   */
  if (*map_to == NUL && !unmenu && enable == MAYBE) {
    show_menus(menu_path, modes);
    goto theend;
  } else if (*map_to != NUL && (unmenu || enable != MAYBE)) {
    EMSG(_(e_trailing));
    goto theend;
  }

  if (enable != MAYBE) {
    /*
     * Change sensitivity of the menu.
     * For the PopUp menu, remove a menu for each mode separately.
     * Careful: menu_nable_recurse() changes menu_path.
     */
    if (STRCMP(menu_path, "*") == 0)            /* meaning: do all menus */
      menu_path = (char_u *)"";

    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          menu_nable_recurse(root_menu, p, MENU_ALL_MODES, enable);
          free(p);
        }
    }
    menu_nable_recurse(root_menu, menu_path, modes, enable);
  } else if (unmenu) {
    /*
     * Delete menu(s).
     */
    if (STRCMP(menu_path, "*") == 0)            /* meaning: remove all menus */
      menu_path = (char_u *)"";

    /*
     * For the PopUp menu, remove a menu for each mode separately.
     */
    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          remove_menu(&root_menu, p, MENU_ALL_MODES, TRUE);
          free(p);
        }
    }

    /* Careful: remove_menu() changes menu_path */
    remove_menu(&root_menu, menu_path, modes, FALSE);
  } else {
    /*
     * Add menu(s).
     * Replace special key codes.
     */
    if (STRICMP(map_to, "<nop>") == 0) {        /* "<Nop>" means nothing */
      map_to = (char_u *)"";
      map_buf = NULL;
    } else if (modes & MENU_TIP_MODE)
      map_buf = NULL;           /* Menu tips are plain text. */
    else
      map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
    menuarg.modes = modes;
    menuarg.noremap[0] = noremap;
    menuarg.silent[0] = silent;
    add_menu_path(menu_path, &menuarg, pri_tab, map_to
        );

    /*
     * For the PopUp menu, add a menu for each mode separately.
     */
    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          // Include all modes, to make ":amenu" work
          menuarg.modes = modes;
          add_menu_path(p, &menuarg, pri_tab, map_to);
          free(p);
        }
    }

    free(map_buf);
  }


theend:
  ;
}