7052 lines · 167.8 KB · C
RawDownload
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved	by Bram Moolenaar * * Do ":help uganda"  in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * ex_cmds.c: some functions for command line commands */ #include "vim.h"#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#include "version.h" #ifdef FEAT_EX_EXTRAstatic int linelen __ARGS((int *has_tab));#endifstatic void do_filter __ARGS((linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd, int do_in, int do_out));#ifdef FEAT_VIMINFOstatic char_u *viminfo_filename __ARGS((char_u	*));static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info, int want_marks, int force_read));static int viminfo_encoding __ARGS((vir_T *virp));static int read_viminfo_up_to_marks __ARGS((vir_T *virp, int forceit, int writing));#endif static int check_overwrite __ARGS((exarg_T *eap, buf_T *buf, char_u *fname, char_u *ffname, int other));static int check_readonly __ARGS((int *forceit, buf_T *buf));#ifdef FEAT_AUTOCMDstatic void delbuf_msg __ARGS((char_u *name));#endifstatic int#ifdef __BORLANDC__    _RTLENTRYF#endif	help_compare __ARGS((const void *s1, const void *s2)); /* * ":ascii" and "ga". *//*ARGSUSED*/    voiddo_ascii(eap)    exarg_T	*eap;{    int		c;    char	buf1[20];    char	buf2[20];    char_u	buf3[7];#ifdef FEAT_MBYTE    int		cc[MAX_MCO];    int		ci = 0;    int		len;     if (enc_utf8)	c = utfc_ptr2char(ml_get_cursor(), cc);    else#endif	c = gchar_cursor();    if (c == NUL)    {	MSG("NUL");	return;    } #ifdef FEAT_MBYTE    IObuff[0] = NUL;    if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80)#endif    {	if (c == NL)	    /* NUL is stored as NL */	    c = NUL;	if (vim_isprintc_strict(c) && (c < ' '#ifndef EBCDIC		    || c > '~'#endif			       ))	{	    transchar_nonprint(buf3, c);	    sprintf(buf1, "  <%s>", (char *)buf3);	}	else	    buf1[0] = NUL;#ifndef EBCDIC	if (c >= 0x80)	    sprintf(buf2, "  <M-%s>", transchar(c & 0x7f));	else#endif	    buf2[0] = NUL;	vim_snprintf((char *)IObuff, IOSIZE,		_("<%s>%s%s  %d,  Hex %02x,  Octal %03o"),					   transchar(c), buf1, buf2, c, c, c);#ifdef FEAT_MBYTE	if (enc_utf8)	    c = cc[ci++];	else	    c = 0;#endif    } #ifdef FEAT_MBYTE    /* Repeat for combining characters. */    while (has_mbyte && (c >= 0x100 || (enc_utf8 && c >= 0x80)))    {	len = (int)STRLEN(IObuff);	/* This assumes every multi-byte char is printable... */	if (len > 0)	    IObuff[len++] = ' ';	IObuff[len++] = '<';	if (enc_utf8 && utf_iscomposing(c)# ifdef USE_GUI		&& !gui.in_use# endif		)	    IObuff[len++] = ' '; /* draw composing char on top of a space */	len += (*mb_char2bytes)(c, IObuff + len);	vim_snprintf((char *)IObuff + len, IOSIZE - len,			c < 0x10000 ? _("> %d, Hex %04x, Octal %o")				    : _("> %d, Hex %08x, Octal %o"), c, c, c);	if (ci == MAX_MCO)	    break;	if (enc_utf8)	    c = cc[ci++];	else	    c = 0;    }#endif     msg(IObuff);} #if defined(FEAT_EX_EXTRA) || defined(PROTO)/* * ":left", ":center" and ":right": align text. */    voidex_align(eap)    exarg_T	*eap;{    pos_T	save_curpos;    int		len;    int		indent = 0;    int		new_indent;    int		has_tab;    int		width; #ifdef FEAT_RIGHTLEFT    if (curwin->w_p_rl)    {	/* switch left and right aligning */	if (eap->cmdidx == CMD_right)	    eap->cmdidx = CMD_left;	else if (eap->cmdidx == CMD_left)	    eap->cmdidx = CMD_right;    }#endif     width = atoi((char *)eap->arg);    save_curpos = curwin->w_cursor;    if (eap->cmdidx == CMD_left)    /* width is used for new indent */    {	if (width >= 0)	    indent = width;    }    else    {	/*	 * if 'textwidth' set, use it	 * else if 'wrapmargin' set, use it	 * if invalid value, use 80	 */	if (width <= 0)	    width = curbuf->b_p_tw;	if (width == 0 && curbuf->b_p_wm > 0)	    width = W_WIDTH(curwin) - curbuf->b_p_wm;	if (width <= 0)	    width = 80;    }     if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)	return;     for (curwin->w_cursor.lnum = eap->line1;		 curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum)    {	if (eap->cmdidx == CMD_left)		/* left align */	    new_indent = indent;	else	{	    has_tab = FALSE;	/* avoid uninit warnings */	    len = linelen(eap->cmdidx == CMD_right ? &has_tab						   : NULL) - get_indent(); 	    if (len <= 0)			/* skip blank lines */		continue; 	    if (eap->cmdidx == CMD_center)		new_indent = (width - len) / 2;	    else	    {		new_indent = width - len;	/* right align */ 		/*		 * Make sure that embedded TABs don't make the text go too far		 * to the right.		 */		if (has_tab)		    while (new_indent > 0)		    {			(void)set_indent(new_indent, 0);			if (linelen(NULL) <= width)			{			    /*			     * Now try to move the line as much as possible to			     * the right.  Stop when it moves too far.			     */			    do				(void)set_indent(++new_indent, 0);			    while (linelen(NULL) <= width);			    --new_indent;			    break;			}			--new_indent;		    }	    }	}	if (new_indent < 0)	    new_indent = 0;	(void)set_indent(new_indent, 0);		/* set indent */    }    changed_lines(eap->line1, 0, eap->line2 + 1, 0L);    curwin->w_cursor = save_curpos;    beginline(BL_WHITE | BL_FIX);} /* * Get the length of the current line, excluding trailing white space. */    static intlinelen(has_tab)    int	    *has_tab;{    char_u  *line;    char_u  *first;    char_u  *last;    int	    save;    int	    len;     /* find the first non-blank character */    line = ml_get_curline();    first = skipwhite(line);     /* find the character after the last non-blank character */    for (last = first + STRLEN(first);				last > first && vim_iswhite(last[-1]); --last)	;    save = *last;    *last = NUL;    len = linetabsize(line);		/* get line length */    if (has_tab != NULL)		/* check for embedded TAB */	*has_tab = (vim_strrchr(first, TAB) != NULL);    *last = save;     return len;} /* Buffer for two lines used during sorting.  They are allocated to * contain the longest line being sorted. */static char_u	*sortbuf1;static char_u	*sortbuf2; static int	sort_ic;		/* ignore case */static int	sort_nr;		/* sort on number */static int	sort_rx;		/* sort on regex instead of skipping it */ static int	sort_abort;		/* flag to indicate if sorting has been interrupted */ /* Struct to store info to be sorted. */typedef struct{    linenr_T	lnum;			/* line number */    long	start_col_nr;		/* starting column number or number */    long	end_col_nr;		/* ending column number */} sorti_T; static int#ifdef __BORLANDC___RTLENTRYF#endifsort_compare __ARGS((const void *s1, const void *s2));     static int#ifdef __BORLANDC___RTLENTRYF#endifsort_compare(s1, s2)    const void	*s1;    const void	*s2;{    sorti_T	l1 = *(sorti_T *)s1;    sorti_T	l2 = *(sorti_T *)s2;    int		result = 0;     /* If the user interrupts, there's no way to stop qsort() immediately, but     * if we return 0 every time, qsort will assume it's done sorting and     * exit. */    if (sort_abort)	return 0;    fast_breakcheck();    if (got_int)	sort_abort = TRUE;     /* When sorting numbers "start_col_nr" is the number, not the column     * number. */    if (sort_nr)	result = l1.start_col_nr - l2.start_col_nr;    else    {	/* We need to copy one line into "sortbuf1", because there is no	 * guarantee that the first pointer becomes invalid when obtaining the	 * second one. */	STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,					 l1.end_col_nr - l1.start_col_nr + 1);	sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;	STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,					 l2.end_col_nr - l2.start_col_nr + 1);	sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; 	result = sort_ic ? STRICMP(sortbuf1, sortbuf2)						 : STRCMP(sortbuf1, sortbuf2);    }     /* If two lines have the same value, preserve the original line order. */    if (result == 0)	return (int)(l1.lnum - l2.lnum);    return result;} /* * ":sort". */    voidex_sort(eap)    exarg_T	*eap;{    regmatch_T	regmatch;    int		len;    linenr_T	lnum;    long	maxlen = 0;    sorti_T	*nrs;    size_t	count = eap->line2 - eap->line1 + 1;    size_t	i;    char_u	*p;    char_u	*s;    char_u	*s2;    char_u	c;			/* temporary character storage */    int		unique = FALSE;    long	deleted;    colnr_T	start_col;    colnr_T	end_col;    int		sort_oct;		/* sort on octal number */    int		sort_hex;		/* sort on hex number */     if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)	return;    sortbuf1 = NULL;    sortbuf2 = NULL;    regmatch.regprog = NULL;    nrs = (sorti_T *)lalloc((long_u)(count * sizeof(sorti_T)), TRUE);    if (nrs == NULL)	goto sortend;     sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;     for (p = eap->arg; *p != NUL; ++p)    {	if (vim_iswhite(*p))	    ;	else if (*p == 'i')	    sort_ic = TRUE;	else if (*p == 'r')	    sort_rx = TRUE;	else if (*p == 'n')	    sort_nr = 2;	else if (*p == 'o')	    sort_oct = 2;	else if (*p == 'x')	    sort_hex = 2;	else if (*p == 'u')	    unique = TRUE;	else if (*p == '"')	/* comment start */	    break;	else if (check_nextcmd(p) != NULL)	{	    eap->nextcmd = check_nextcmd(p);	    break;	}	else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)	{	    s = skip_regexp(p + 1, *p, TRUE, NULL);	    if (*s != *p)	    {		EMSG(_(e_invalpat));		goto sortend;	    }	    *s = NUL;	    regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);	    if (regmatch.regprog == NULL)		goto sortend;	    p = s;		/* continue after the regexp */	    regmatch.rm_ic = p_ic;	}	else	{	    EMSG2(_(e_invarg2), p);	    goto sortend;	}    }     /* Can only have one of 'n', 'o' and 'x'. */    if (sort_nr + sort_oct + sort_hex > 2)    {	EMSG(_(e_invarg));	goto sortend;    }     /* From here on "sort_nr" is used as a flag for any number sorting. */    sort_nr += sort_oct + sort_hex;     /*     * Make an array with all line numbers.  This avoids having to copy all     * the lines into allocated memory.     * When sorting on strings "start_col_nr" is the offset in the line, for     * numbers sorting it's the number to sort on.  This means the pattern     * matching and number conversion only has to be done once per line.     * Also get the longest line length for allocating "sortbuf".     */    for (lnum = eap->line1; lnum <= eap->line2; ++lnum)    {	s = ml_get(lnum);	len = (int)STRLEN(s);	if (maxlen < len)	    maxlen = len; 	start_col = 0;	end_col = len;	if (regmatch.regprog != NULL && vim_regexec(&regmatch, s, 0))	{	    if (sort_rx)	    {		start_col = (colnr_T)(regmatch.startp[0] - s);		end_col = (colnr_T)(regmatch.endp[0] - s);	    }	    else		start_col = (colnr_T)(regmatch.endp[0] - s);	}	else	    if (regmatch.regprog != NULL)		end_col = 0; 	if (sort_nr)	{	    /* Make sure vim_str2nr doesn't read any digits past the end	     * of the match, by temporarily terminating the string there */	    s2 = s + end_col;	    c = *s2;	    (*s2) = 0;	    /* Sorting on number: Store the number itself. */	    if (sort_hex)		s = skiptohex(s + start_col);	    else		s = skiptodigit(s + start_col);	    vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,					&nrs[lnum - eap->line1].start_col_nr, NULL);	    (*s2) = c;	}	else	{	    /* Store the column to sort at. */	    nrs[lnum - eap->line1].start_col_nr = start_col;	    nrs[lnum - eap->line1].end_col_nr = end_col;	} 	nrs[lnum - eap->line1].lnum = lnum; 	if (regmatch.regprog != NULL)	    fast_breakcheck();	if (got_int)	    goto sortend;    }     /* Allocate a buffer that can hold the longest line. */    sortbuf1 = alloc((unsigned)maxlen + 1);    if (sortbuf1 == NULL)	goto sortend;    sortbuf2 = alloc((unsigned)maxlen + 1);

Lines 1–500 of 7052.