Skip to content
Snippets Groups Projects
ex_cmds2.c 127 KiB
Newer Older
	}

	/*
	 * Check for ^C here now and then, so recursive :so can be broken.
	 */
	line_breakcheck();
	break;
    }

    if (have_read)
	return (char_u *)ga.ga_data;

    vim_free(ga.ga_data);
    return NULL;
}

#if defined(FEAT_PROFILE) || defined(PROTO)
/*
 * Called when starting to read a script line.
 * "sourcing_lnum" must be correct!
 * When skipping lines it may not actually be executed, but we won't find out
 * until later and we need to store the time now.
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
script_line_start(void)
{
    scriptitem_T    *si;
    sn_prl_T	    *pp;

    if (current_SID <= 0 || current_SID > script_items.ga_len)
	return;
    si = &SCRIPT_ITEM(current_SID);
    if (si->sn_prof_on && sourcing_lnum >= 1)
    {
Bram Moolenaar's avatar
Bram Moolenaar committed
	/* Grow the array before starting the timer, so that the time spent
	 * here isn't counted. */
	(void)ga_grow(&si->sn_prl_ga,
				  (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
	si->sn_prl_idx = sourcing_lnum - 1;
	while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
		&& si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
	{
	    /* Zero counters for a line that was not used before. */
	    pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
	    pp->snp_count = 0;
	    profile_zero(&pp->sn_prl_total);
	    profile_zero(&pp->sn_prl_self);
	    ++si->sn_prl_ga.ga_len;
	}
	si->sn_prl_execed = FALSE;
	profile_start(&si->sn_prl_start);
	profile_zero(&si->sn_prl_children);
	profile_get_wait(&si->sn_prl_wait);
    }
}

/*
 * Called when actually executing a function line.
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
script_line_exec(void)
{
    scriptitem_T    *si;

    if (current_SID <= 0 || current_SID > script_items.ga_len)
	return;
    si = &SCRIPT_ITEM(current_SID);
    if (si->sn_prof_on && si->sn_prl_idx >= 0)
	si->sn_prl_execed = TRUE;
}

/*
 * Called when done with a script line.
Bram Moolenaar's avatar
Bram Moolenaar committed
script_line_end(void)
{
    scriptitem_T    *si;
    sn_prl_T	    *pp;

    if (current_SID <= 0 || current_SID > script_items.ga_len)
	return;
    si = &SCRIPT_ITEM(current_SID);
    if (si->sn_prof_on && si->sn_prl_idx >= 0
				     && si->sn_prl_idx < si->sn_prl_ga.ga_len)
    {
	if (si->sn_prl_execed)
	{
	    pp = &PRL_ITEM(si, si->sn_prl_idx);
	    ++pp->snp_count;
	    profile_end(&si->sn_prl_start);
	    profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
	    profile_add(&pp->sn_prl_total, &si->sn_prl_start);
	    profile_self(&pp->sn_prl_self, &si->sn_prl_start,
							&si->sn_prl_children);
	}
	si->sn_prl_idx = -1;
    }
}
#endif

/*
 * ":scriptencoding": Set encoding conversion for a sourced script.
 * Without the multi-byte feature it's simply ignored.
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
ex_scriptencoding(exarg_T *eap UNUSED)
{
#ifdef FEAT_MBYTE
    struct source_cookie	*sp;
    char_u			*name;

    if (!getline_equal(eap->getline, eap->cookie, getsourceline))
    {
	EMSG(_("E167: :scriptencoding used outside of a sourced file"));
	return;
    }

    if (*eap->arg != NUL)
    {
	name = enc_canonize(eap->arg);
	if (name == NULL)	/* out of memory */
	    return;
    }
    else
	name = eap->arg;

    /* Setup for conversion from the specified encoding to 'encoding'. */
    sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
    convert_setup(&sp->conv, name, p_enc);

    if (name != eap->arg)
	vim_free(name);
#endif
}

#if defined(FEAT_EVAL) || defined(PROTO)
/*
 * ":finish": Mark a sourced file as finished.
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
ex_finish(exarg_T *eap)
{
    if (getline_equal(eap->getline, eap->cookie, getsourceline))
	do_finish(eap, FALSE);
    else
	EMSG(_("E168: :finish used outside of a sourced file"));
}

/*
 * Mark a sourced file as finished.  Possibly makes the ":finish" pending.
 * Also called for a pending finish at the ":endtry" or after returning from
 * an extra do_cmdline().  "reanimate" is used in the latter case.
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
do_finish(exarg_T *eap, int reanimate)
{
    int		idx;

    if (reanimate)
	((struct source_cookie *)getline_cookie(eap->getline,
					      eap->cookie))->finished = FALSE;

    /*
     * Cleanup (and inactivate) conditionals, but stop when a try conditional
     * not in its finally clause (which then is to be executed next) is found.
     * In this case, make the ":finish" pending for execution at the ":endtry".
     * Otherwise, finish normally.
     */
    idx = cleanup_conditionals(eap->cstack, 0, TRUE);
    if (idx >= 0)
    {
	eap->cstack->cs_pending[idx] = CSTP_FINISH;
	report_make_pending(CSTP_FINISH, NULL);
    }
    else
	((struct source_cookie *)getline_cookie(eap->getline,
					       eap->cookie))->finished = TRUE;
}


/*
 * Return TRUE when a sourced file had the ":finish" command: Don't give error
 * message for missing ":endif".
 * Return FALSE when not sourcing a file.
 */
    int
Bram Moolenaar's avatar
Bram Moolenaar committed
source_finished(
    char_u	*(*fgetline)(int, void *, int),
    void	*cookie)
    return (getline_equal(fgetline, cookie, getsourceline)
	    && ((struct source_cookie *)getline_cookie(
						fgetline, cookie))->finished);
}
#endif

/*
 * ":checktime [buffer]"
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
ex_checktime(exarg_T *eap)
{
    buf_T	*buf;
    int		save_no_check_timestamps = no_check_timestamps;

    no_check_timestamps = 0;
    if (eap->addr_count == 0)	/* default is all buffers */
	check_timestamps(FALSE);
    else
    {
	buf = buflist_findnr((int)eap->line2);
	if (buf != NULL)	/* cannot happen? */
	    (void)buf_check_timestamp(buf, FALSE);
    }
    no_check_timestamps = save_no_check_timestamps;
}

#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
	&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar's avatar
Bram Moolenaar committed
static char_u *get_locale_val(int what);
Bram Moolenaar's avatar
Bram Moolenaar committed
    static char_u *
Bram Moolenaar's avatar
Bram Moolenaar committed
get_locale_val(int what)
Bram Moolenaar's avatar
Bram Moolenaar committed
    char_u	*loc;
Bram Moolenaar's avatar
Bram Moolenaar committed
    /* Obtain the locale value from the libraries. */
Bram Moolenaar's avatar
Bram Moolenaar committed
    loc = (char_u *)setlocale(what, NULL);
# ifdef WIN32
    if (loc != NULL)
    {
	char_u	*p;

	/* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
	 * one of the values (e.g., LC_CTYPE) differs. */
	p = vim_strchr(loc, '=');
	if (p != NULL)
	{
	    loc = ++p;
	    while (*p != NUL)	/* remove trailing newline */
	    {
		if (*p < ' ' || *p == ';')
		{
		    *p = NUL;
		    break;
		}
		++p;
	    }
	}
    }
# endif

    return loc;
}
#endif


#ifdef WIN32
/*
 * On MS-Windows locale names are strings like "German_Germany.1252", but
 * gettext expects "de".  Try to translate one into another here for a few
 * supported languages.
 */
    static char_u *
gettext_lang(char_u *name)
{
    int		i;
    static char *(mtable[]) = {
			"afrikaans",	"af",
			"czech",	"cs",
			"dutch",	"nl",
			"german",	"de",
			"english_united kingdom", "en_GB",
			"spanish",	"es",
			"french",	"fr",
			"italian",	"it",
			"japanese",	"ja",
			"korean",	"ko",
			"norwegian",	"no",
			"polish",	"pl",
			"russian",	"ru",
			"slovak",	"sk",
			"swedish",	"sv",
			"ukrainian",	"uk",
			"chinese_china", "zh_CN",
			"chinese_taiwan", "zh_TW",
			NULL};

    for (i = 0; mtable[i] != NULL; i += 2)
	if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar's avatar
Bram Moolenaar committed
	    return (char_u *)mtable[i + 1];
    return name;
}
#endif

#if defined(FEAT_MULTI_LANG) || defined(PROTO)
/*
 * Obtain the current messages language.  Used to set the default for
 * 'helplang'.  May return NULL or an empty string.
 */
    char_u *
Bram Moolenaar's avatar
Bram Moolenaar committed
get_mess_lang(void)
#  if defined(LC_MESSAGES)
Bram Moolenaar's avatar
Bram Moolenaar committed
    p = get_locale_val(LC_MESSAGES);
#  else
    /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
     * may be set to the LCID number.  LC_COLLATE is the best guess, LC_TIME
     * and LC_MONETARY may be set differently for a Japanese working in the
     * US. */
Bram Moolenaar's avatar
Bram Moolenaar committed
    p = get_locale_val(LC_COLLATE);
#  endif
# else
    p = mch_getenv((char_u *)"LC_ALL");
    if (p == NULL || *p == NUL)
    {
	p = mch_getenv((char_u *)"LC_MESSAGES");
	if (p == NULL || *p == NUL)
	    p = mch_getenv((char_u *)"LANG");
    }
# endif
# ifdef WIN32
    p = gettext_lang(p);
# endif
    return p;
}
#endif

/* Complicated #if; matches with where get_mess_env() is used below. */
#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
	    && defined(LC_MESSAGES))) \
	|| ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
		&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
		&& !defined(LC_MESSAGES))
Bram Moolenaar's avatar
Bram Moolenaar committed
static char_u *get_mess_env(void);

/*
 * Get the language used for messages from the environment.
 */
    static char_u *
Bram Moolenaar's avatar
Bram Moolenaar committed
get_mess_env(void)
{
    char_u	*p;

    p = mch_getenv((char_u *)"LC_ALL");
    if (p == NULL || *p == NUL)
    {
	p = mch_getenv((char_u *)"LC_MESSAGES");
	if (p == NULL || *p == NUL)
	{
	    p = mch_getenv((char_u *)"LANG");
	    if (p != NULL && VIM_ISDIGIT(*p))
		p = NULL;		/* ignore something like "1043" */
	    if (p == NULL || *p == NUL)
Bram Moolenaar's avatar
Bram Moolenaar committed
		p = get_locale_val(LC_CTYPE);
# endif
	}
    }
    return p;
}
#endif

#if defined(FEAT_EVAL) || defined(PROTO)

/*
 * Set the "v:lang" variable according to the current locale setting.
 * Also do "v:lc_time"and "v:ctype".
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
set_lang_var(void)
Bram Moolenaar's avatar
Bram Moolenaar committed
    loc = get_locale_val(LC_CTYPE);
# else
    /* setlocale() not supported: use the default value */
    loc = (char_u *)"C";
# endif
    set_vim_var_string(VV_CTYPE, loc, -1);

    /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
     * back to LC_CTYPE if it's empty. */
# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar's avatar
Bram Moolenaar committed
    loc = get_locale_val(LC_MESSAGES);
# else
    loc = get_mess_env();
# endif
    set_vim_var_string(VV_LANG, loc, -1);

Bram Moolenaar's avatar
Bram Moolenaar committed
    loc = get_locale_val(LC_TIME);
# endif
    set_vim_var_string(VV_LC_TIME, loc, -1);
}
#endif

#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
	&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
/*
 * ":language":  Set the language (locale).
 */
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
ex_language(exarg_T *eap)
{
    char	*loc;
    char_u	*p;
    char_u	*name;
    int		what = LC_ALL;
    char	*whatstr = "";
#ifdef LC_MESSAGES
# define VIM_LC_MESSAGES LC_MESSAGES
#else
# define VIM_LC_MESSAGES 6789
#endif

    name = eap->arg;

    /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
     * Allow abbreviation, but require at least 3 characters to avoid
     * confusion with a two letter language name "me" or "ct". */
    p = skiptowhite(eap->arg);
    if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
    {
	if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
	{
	    what = VIM_LC_MESSAGES;
	    name = skipwhite(p);
	    whatstr = "messages ";
	}
	else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
	{
	    what = LC_CTYPE;
	    name = skipwhite(p);
	    whatstr = "ctype ";
	}
	else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
	{
	    what = LC_TIME;
	    name = skipwhite(p);
	    whatstr = "time ";
	}
    }

    if (*name == NUL)
    {
#ifndef LC_MESSAGES
	if (what == VIM_LC_MESSAGES)
	    p = get_mess_env();
	else
#endif
	    p = (char_u *)setlocale(what, NULL);
	if (p == NULL || *p == NUL)
	    p = (char_u *)"Unknown";
	smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
    }
    else
    {
#ifndef LC_MESSAGES
	if (what == VIM_LC_MESSAGES)
	    loc = "";
	else
#endif
	    loc = setlocale(what, (char *)name);
Bram Moolenaar's avatar
Bram Moolenaar committed
#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
	    /* Make sure strtod() uses a decimal point, not a comma. */
	    setlocale(LC_NUMERIC, "C");
#endif
	}
	if (loc == NULL)
	    EMSG2(_("E197: Cannot set language to \"%s\""), name);
	else
	{
#ifdef HAVE_NL_MSG_CAT_CNTR
	    /* Need to do this for GNU gettext, otherwise cached translations
	     * will be used again. */
	    extern int _nl_msg_cat_cntr;

	    ++_nl_msg_cat_cntr;
#endif
Bram Moolenaar's avatar
Bram Moolenaar committed
	    /* Reset $LC_ALL, otherwise it would overrule everything. */
	    vim_setenv((char_u *)"LC_ALL", (char_u *)"");

	    if (what != LC_TIME)
	    {
		/* Tell gettext() what to translate to.  It apparently doesn't
		 * use the currently effective locale.  Also do this when
		 * FEAT_GETTEXT isn't defined, so that shell commands use this
		 * value. */
		if (what == LC_ALL)
		    vim_setenv((char_u *)"LANG", name);

		    /* Clear $LANGUAGE because GNU gettext uses it. */
		    vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
# ifdef WIN32
		    /* Apparently MS-Windows printf() may cause a crash when
		     * we give it 8-bit text while it's expecting text in the
		     * current locale.  This call avoids that. */
		    setlocale(LC_CTYPE, "C");
# endif
		}
		if (what != LC_CTYPE)
		{
		    char_u	*mname;
#ifdef WIN32
		    mname = gettext_lang(name);
#else
		    mname = name;
#endif
		    vim_setenv((char_u *)"LC_MESSAGES", mname);
#ifdef FEAT_MULTI_LANG
		    set_helplang_default(mname);
#endif
		}
	    }

# ifdef FEAT_EVAL
	    /* Set v:lang, v:lc_time and v:ctype to the final result. */
	    set_lang_var();
# endif
# ifdef FEAT_TITLE
	    maketitle();
# endif
	}
    }
}

# if defined(FEAT_CMDL_COMPL) || defined(PROTO)

static char_u	**locales = NULL;	/* Array of all available locales */

#  ifndef WIN32
static int	did_init_locales = FALSE;

/* Return an array of strings for all available locales + NULL for the
 * last element.  Return NULL in case of error. */
    static char_u **
Bram Moolenaar's avatar
Bram Moolenaar committed
find_locales(void)
{
    garray_T	locales_ga;
    char_u	*loc;

    /* Find all available locales by running command "locale -a".  If this
     * doesn't work we won't have completion. */
    char_u *locale_a = get_cmd_output((char_u *)"locale -a",
						    NULL, SHELL_SILENT, NULL);
    if (locale_a == NULL)
	return NULL;
    ga_init2(&locales_ga, sizeof(char_u *), 20);

    /* Transform locale_a string where each locale is separated by "\n"
     * into an array of locale strings. */
    loc = (char_u *)strtok((char *)locale_a, "\n");

    while (loc != NULL)
    {
	if (ga_grow(&locales_ga, 1) == FAIL)
	    break;
	loc = vim_strsave(loc);
	if (loc == NULL)
	    break;

	((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
	loc = (char_u *)strtok(NULL, "\n");
    }
    vim_free(locale_a);
    if (ga_grow(&locales_ga, 1) == FAIL)
    {
	ga_clear(&locales_ga);
	return NULL;
    }
    ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
    return (char_u **)locales_ga.ga_data;
}
#  endif

/*
 * Lazy initialization of all available locales.
 */
    static void
init_locales(void)
{
#  ifndef WIN32
    if (!did_init_locales)
    {
	did_init_locales = TRUE;
	locales = find_locales();
    }
#  endif
}

#  if defined(EXITFREE) || defined(PROTO)
    void
Bram Moolenaar's avatar
Bram Moolenaar committed
free_locales(void)
{
    int			i;
    if (locales != NULL)
    {
	for (i = 0; locales[i] != NULL; i++)
	    vim_free(locales[i]);
/*
 * Function given to ExpandGeneric() to obtain the possible arguments of the
 * ":language" command.
 */
    char_u *
Bram Moolenaar's avatar
Bram Moolenaar committed
get_lang_arg(expand_T *xp UNUSED, int idx)
{
    if (idx == 0)
	return (char_u *)"messages";
    if (idx == 1)
	return (char_u *)"ctype";
    if (idx == 2)
	return (char_u *)"time";

    init_locales();
    if (locales == NULL)
	return NULL;
    return locales[idx - 3];
}

/*
 * Function given to ExpandGeneric() to obtain the available locales.
 */
    char_u *
Bram Moolenaar's avatar
Bram Moolenaar committed
get_locales(expand_T *xp UNUSED, int idx)
{
    init_locales();
    if (locales == NULL)
	return NULL;
    return locales[idx];