9419 lines · 220.1 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. */ /* * misc1.c: functions that didn't seem to fit elsewhere */ #include "vim.h"#include "version.h" #ifdef HAVE_FCNTL_H# include <fcntl.h>		/* for chdir() */#endif static char_u *vim_version_dir __ARGS((char_u *vimdir));static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name));static int copy_indent __ARGS((int size, char_u	*src)); /* * Count the size (in window cells) of the indent in the current line. */    intget_indent(){    return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts);} /* * Count the size (in window cells) of the indent in line "lnum". */    intget_indent_lnum(lnum)    linenr_T	lnum;{    return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts);} #if defined(FEAT_FOLDING) || defined(PROTO)/* * Count the size (in window cells) of the indent in line "lnum" of buffer * "buf". */    intget_indent_buf(buf, lnum)    buf_T	*buf;    linenr_T	lnum;{    return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts);}#endif /* * count the size (in window cells) of the indent in line "ptr", with * 'tabstop' at "ts" */    intget_indent_str(ptr, ts)    char_u	*ptr;    int		ts;{    int		count = 0;     for ( ; *ptr; ++ptr)    {	if (*ptr == TAB)    /* count a tab for what it is worth */	    count += ts - (count % ts);	else if (*ptr == ' ')	    ++count;		/* count a space for one */	else	    break;    }    return count;} /* * Set the indent of the current line. * Leaves the cursor on the first non-blank in the line. * Caller must take care of undo. * "flags": *	SIN_CHANGED:	call changed_bytes() if the line was changed. *	SIN_INSERT:	insert the indent in front of the line. *	SIN_UNDO:	save line for undo before changing it. * Returns TRUE if the line was changed. */    intset_indent(size, flags)    int		size;    int		flags;{    char_u	*p;    char_u	*newline;    char_u	*oldline;    char_u	*s;    int		todo;    int		ind_len;    int		line_len;    int		doit = FALSE;    int		ind_done;    int		tab_pad;    int		retval = FALSE;     /*     * First check if there is anything to do and compute the number of     * characters needed for the indent.     */    todo = size;    ind_len = 0;    p = oldline = ml_get_curline();     /* Calculate the buffer size for the new indent, and check to see if it     * isn't already set */     /* if 'expandtab' isn't set: use TABs */    if (!curbuf->b_p_et)    {	/* If 'preserveindent' is set then reuse as much as possible of	 * the existing indent structure for the new indent */	if (!(flags & SIN_INSERT) && curbuf->b_p_pi)	{	    ind_done = 0; 	    /* count as many characters as we can use */	    while (todo > 0 && vim_iswhite(*p))	    {		if (*p == TAB)		{		    tab_pad = (int)curbuf->b_p_ts					   - (ind_done % (int)curbuf->b_p_ts);		    /* stop if this tab will overshoot the target */		    if (todo < tab_pad)			break;		    todo -= tab_pad;		    ++ind_len;		    ind_done += tab_pad;		}		else		{		    --todo;		    ++ind_len;		    ++ind_done;		}		++p;	    } 	    /* Fill to next tabstop with a tab, if possible */	    tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);	    if (todo >= tab_pad)	    {		doit = TRUE;		todo -= tab_pad;		++ind_len;		/* ind_done += tab_pad; */	    }	} 	/* count tabs required for indent */	while (todo >= (int)curbuf->b_p_ts)	{	    if (*p != TAB)		doit = TRUE;	    else		++p;	    todo -= (int)curbuf->b_p_ts;	    ++ind_len;	    /* ind_done += (int)curbuf->b_p_ts; */	}    }    /* count spaces required for indent */    while (todo > 0)    {	if (*p != ' ')	    doit = TRUE;	else	    ++p;	--todo;	++ind_len;	/* ++ind_done; */    }     /* Return if the indent is OK already. */    if (!doit && !vim_iswhite(*p) && !(flags & SIN_INSERT))	return FALSE;     /* Allocate memory for the new line. */    if (flags & SIN_INSERT)	p = oldline;    else	p = skipwhite(p);    line_len = (int)STRLEN(p) + 1;    newline = alloc(ind_len + line_len);    if (newline == NULL)	return FALSE;     /* Put the characters in the new line. */    s = newline;    todo = size;    /* if 'expandtab' isn't set: use TABs */    if (!curbuf->b_p_et)    {	/* If 'preserveindent' is set then reuse as much as possible of	 * the existing indent structure for the new indent */	if (!(flags & SIN_INSERT) && curbuf->b_p_pi)	{	    p = oldline;	    ind_done = 0; 	    while (todo > 0 && vim_iswhite(*p))	    {		if (*p == TAB)		{		    tab_pad = (int)curbuf->b_p_ts					   - (ind_done % (int)curbuf->b_p_ts);		    /* stop if this tab will overshoot the target */		    if (todo < tab_pad)			break;		    todo -= tab_pad;		    ind_done += tab_pad;		}		else		{		    --todo;		    ++ind_done;		}		*s++ = *p++;	    } 	    /* Fill to next tabstop with a tab, if possible */	    tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);	    if (todo >= tab_pad)	    {		*s++ = TAB;		todo -= tab_pad;	    } 	    p = skipwhite(p);	} 	while (todo >= (int)curbuf->b_p_ts)	{	    *s++ = TAB;	    todo -= (int)curbuf->b_p_ts;	}    }    while (todo > 0)    {	*s++ = ' ';	--todo;    }    mch_memmove(s, p, (size_t)line_len);     /* Replace the line (unless undo fails). */    if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK)    {	ml_replace(curwin->w_cursor.lnum, newline, FALSE);	if (flags & SIN_CHANGED)	    changed_bytes(curwin->w_cursor.lnum, 0);	/* Correct saved cursor position if it's after the indent. */	if (saved_cursor.lnum == curwin->w_cursor.lnum				&& saved_cursor.col >= (colnr_T)(p - oldline))	    saved_cursor.col += ind_len - (colnr_T)(p - oldline);	retval = TRUE;    }    else	vim_free(newline);     curwin->w_cursor.col = ind_len;    return retval;} /* * Copy the indent from ptr to the current line (and fill to size) * Leaves the cursor on the first non-blank in the line. * Returns TRUE if the line was changed. */    static intcopy_indent(size, src)    int		size;    char_u	*src;{    char_u	*p = NULL;    char_u	*line = NULL;    char_u	*s;    int		todo;    int		ind_len;    int		line_len = 0;    int		tab_pad;    int		ind_done;    int		round;     /* Round 1: compute the number of characters needed for the indent     * Round 2: copy the characters. */    for (round = 1; round <= 2; ++round)    {	todo = size;	ind_len = 0;	ind_done = 0;	s = src; 	/* Count/copy the usable portion of the source line */	while (todo > 0 && vim_iswhite(*s))	{	    if (*s == TAB)	    {		tab_pad = (int)curbuf->b_p_ts					   - (ind_done % (int)curbuf->b_p_ts);		/* Stop if this tab will overshoot the target */		if (todo < tab_pad)		    break;		todo -= tab_pad;		ind_done += tab_pad;	    }	    else	    {		--todo;		++ind_done;	    }	    ++ind_len;	    if (p != NULL)		*p++ = *s;	    ++s;	} 	/* Fill to next tabstop with a tab, if possible */	tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);	if (todo >= tab_pad)	{	    todo -= tab_pad;	    ++ind_len;	    if (p != NULL)		*p++ = TAB;	} 	/* Add tabs required for indent */	while (todo >= (int)curbuf->b_p_ts)	{	    todo -= (int)curbuf->b_p_ts;	    ++ind_len;	    if (p != NULL)		*p++ = TAB;	} 	/* Count/add spaces required for indent */	while (todo > 0)	{	    --todo;	    ++ind_len;	    if (p != NULL)		*p++ = ' ';	} 	if (p == NULL)	{	    /* Allocate memory for the result: the copied indent, new indent	     * and the rest of the line. */	    line_len = (int)STRLEN(ml_get_curline()) + 1;	    line = alloc(ind_len + line_len);	    if (line == NULL)		return FALSE;	    p = line;	}    }     /* Append the original line */    mch_memmove(p, ml_get_curline(), (size_t)line_len);     /* Replace the line */    ml_replace(curwin->w_cursor.lnum, line, FALSE);     /* Put the cursor after the indent. */    curwin->w_cursor.col = ind_len;    return TRUE;} /* * Return the indent of the current line after a number.  Return -1 if no * number was found.  Used for 'n' in 'formatoptions': numbered list. * Since a pattern is used it can actually handle more than numbers. */    intget_number_indent(lnum)    linenr_T	lnum;{    colnr_T	col;    pos_T	pos;    regmmatch_T	regmatch;     if (lnum > curbuf->b_ml.ml_line_count)	return -1;    pos.lnum = 0;    regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);    if (regmatch.regprog != NULL)    {	regmatch.rmm_ic = FALSE;	regmatch.rmm_maxcol = 0;	if (vim_regexec_multi(&regmatch, curwin, curbuf, lnum, (colnr_T)0))	{	    pos.lnum = regmatch.endpos[0].lnum + lnum;	    pos.col = regmatch.endpos[0].col;#ifdef FEAT_VIRTUALEDIT	    pos.coladd = 0;#endif	}	vim_free(regmatch.regprog);    }     if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)	return -1;    getvcol(curwin, &pos, &col, NULL, NULL);    return (int)col;} #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) static int cin_is_cinword __ARGS((char_u *line)); /* * Return TRUE if the string "line" starts with a word from 'cinwords'. */    static intcin_is_cinword(line)    char_u	*line;{    char_u	*cinw;    char_u	*cinw_buf;    int		cinw_len;    int		retval = FALSE;    int		len;     cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;    cinw_buf = alloc((unsigned)cinw_len);    if (cinw_buf != NULL)    {	line = skipwhite(line);	for (cinw = curbuf->b_p_cinw; *cinw; )	{	    len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");	    if (STRNCMP(line, cinw_buf, len) == 0		    && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))	    {		retval = TRUE;		break;	    }	}	vim_free(cinw_buf);    }    return retval;}#endif /* * open_line: Add a new line below or above the current line. * * For VREPLACE mode, we only add a new line when we get to the end of the * file, otherwise we just start replacing the next line. * * Caller must take care of undo.  Since VREPLACE may affect any number of * lines however, it may call u_save_cursor() again when starting to change a * new line. * "flags": OPENLINE_DELSPACES	delete spaces after cursor *	    OPENLINE_DO_COM	format comments *	    OPENLINE_KEEPTRAIL	keep trailing spaces *	    OPENLINE_MARKFIX	adjust mark positions after the line break * * Return TRUE for success, FALSE for failure */    intopen_line(dir, flags, old_indent)    int		dir;		/* FORWARD or BACKWARD */    int		flags;    int		old_indent;	/* indent for after ^^D in Insert mode */{    char_u	*saved_line;		/* copy of the original line */    char_u	*next_line = NULL;	/* copy of the next line */    char_u	*p_extra = NULL;	/* what goes to next line */    int		less_cols = 0;		/* less columns for mark in new line */    int		less_cols_off = 0;	/* columns to skip for mark adjust */    pos_T	old_cursor;		/* old cursor position */    int		newcol = 0;		/* new cursor column */    int		newindent = 0;		/* auto-indent of the new line */    int		n;    int		trunc_line = FALSE;	/* truncate current line afterwards */    int		retval = FALSE;		/* return value, default is FAIL */#ifdef FEAT_COMMENTS    int		extra_len = 0;		/* length of p_extra string */    int		lead_len;		/* length of comment leader */    char_u	*lead_flags;	/* position in 'comments' for comment leader */    char_u	*leader = NULL;		/* copy of comment leader */#endif    char_u	*allocated = NULL;	/* allocated memory */#if defined(FEAT_SMARTINDENT) || defined(FEAT_VREPLACE) || defined(FEAT_LISP) \	|| defined(FEAT_CINDENT) || defined(FEAT_COMMENTS)    char_u	*p;#endif    int		saved_char = NUL;	/* init for GCC */

Lines 1–500 of 9419.