4049 lines · 91.0 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_cmds2.c: some more functions for command line commands */ #if defined(WIN32) && defined(FEAT_CSCOPE)# include "vimio.h"#endif #include "vim.h" #if defined(WIN32) && defined(FEAT_CSCOPE)# include <fcntl.h>#endif #include "version.h" static void	cmd_source __ARGS((char_u *fname, exarg_T *eap)); #ifdef FEAT_EVAL/* Growarray to store info about already sourced scripts. * For Unix also store the dev/ino, so that we don't have to stat() each * script when going through the list. */typedef struct scriptitem_S{    char_u	*sn_name;# ifdef UNIX    int		sn_dev;    ino_t	sn_ino;# endif# ifdef FEAT_PROFILE    int		sn_prof_on;	/* TRUE when script is/was profiled */    int		sn_pr_force;	/* forceit: profile functions in this script */    proftime_T	sn_pr_child;	/* time set when going into first child */    int		sn_pr_nest;	/* nesting for sn_pr_child */    /* profiling the script as a whole */    int		sn_pr_count;	/* nr of times sourced */    proftime_T	sn_pr_total;	/* time spend in script + children */    proftime_T	sn_pr_self;	/* time spend in script itself */    proftime_T	sn_pr_start;	/* time at script start */    proftime_T	sn_pr_children; /* time in children after script start */    /* profiling the script per line */    garray_T	sn_prl_ga;	/* things stored for every line */    proftime_T	sn_prl_start;	/* start time for current line */    proftime_T	sn_prl_children; /* time spent in children for this line */    proftime_T	sn_prl_wait;	/* wait start time for current line */    int		sn_prl_idx;	/* index of line being timed; -1 if none */    int		sn_prl_execed;	/* line being timed was executed */# endif} scriptitem_T; static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1]) # ifdef FEAT_PROFILE/* Struct used in sn_prl_ga for every line of a script. */typedef struct sn_prl_S{    int		snp_count;	/* nr of times line was executed */    proftime_T	sn_prl_total;	/* time spend in a line + children */    proftime_T	sn_prl_self;	/* time spend in a line itself */} sn_prl_T; #  define PRL_ITEM(si, idx)	(((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])# endif#endif #if defined(FEAT_EVAL) || defined(PROTO)static int debug_greedy = FALSE;	/* batch mode debugging: don't save					   and restore typeahead. */ /* * do_debug(): Debug mode. * Repeatedly get Ex commands, until told to continue normal execution. */    voiddo_debug(cmd)    char_u	*cmd;{    int		save_msg_scroll = msg_scroll;    int		save_State = State;    int		save_did_emsg = did_emsg;    int		save_cmd_silent = cmd_silent;    int		save_msg_silent = msg_silent;    int		save_emsg_silent = emsg_silent;    int		save_redir_off = redir_off;    tasave_T	typeaheadbuf;# ifdef FEAT_EX_EXTRA    int		save_ex_normal_busy;# endif    int		n;    char_u	*cmdline = NULL;    char_u	*p;    char	*tail = NULL;    static int	last_cmd = 0;#define CMD_CONT	1#define CMD_NEXT	2#define CMD_STEP	3#define CMD_FINISH	4#define CMD_QUIT	5#define CMD_INTERRUPT	6 #ifdef ALWAYS_USE_GUI    /* Can't do this when there is no terminal for input/output. */    if (!gui.in_use)    {	/* Break as soon as possible. */	debug_break_level = 9999;	return;    }#endif     /* Make sure we are in raw mode and start termcap mode.  Might have side     * effects... */    settmode(TMODE_RAW);    starttermcap();     ++RedrawingDisabled;	/* don't redisplay the window */    ++no_wait_return;		/* don't wait for return */    did_emsg = FALSE;		/* don't use error from debugged stuff */    cmd_silent = FALSE;		/* display commands */    msg_silent = FALSE;		/* display messages */    emsg_silent = FALSE;	/* display error messages */    redir_off = TRUE;		/* don't redirect debug commands */     State = NORMAL;#ifdef FEAT_SNIFF    want_sniff_request = 0;    /* No K_SNIFF wanted */#endif     if (!debug_did_msg)	MSG(_("Entering Debug mode.  Type \"cont\" to continue."));    if (sourcing_name != NULL)	msg(sourcing_name);    if (sourcing_lnum != 0)	smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);    else	smsg((char_u *)_("cmd: %s"), cmd);     /*     * Repeat getting a command and executing it.     */    for (;;)    {	msg_scroll = TRUE;	need_wait_return = FALSE;#ifdef FEAT_SNIFF	ProcessSniffRequests();#endif	/* Save the current typeahead buffer and replace it with an empty one.	 * This makes sure we get input from the user here and don't interfere	 * with the commands being executed.  Reset "ex_normal_busy" to avoid	 * the side effects of using ":normal". Save the stuff buffer and make	 * it empty. */# ifdef FEAT_EX_EXTRA	save_ex_normal_busy = ex_normal_busy;	ex_normal_busy = 0;# endif	if (!debug_greedy)	    save_typeahead(&typeaheadbuf); 	cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL); 	if (!debug_greedy)	    restore_typeahead(&typeaheadbuf);# ifdef FEAT_EX_EXTRA	ex_normal_busy = save_ex_normal_busy;# endif 	cmdline_row = msg_row;	if (cmdline != NULL)	{	    /* If this is a debug command, set "last_cmd".	     * If not, reset "last_cmd".	     * For a blank line use previous command. */	    p = skipwhite(cmdline);	    if (*p != NUL)	    {		switch (*p)		{		    case 'c': last_cmd = CMD_CONT;			      tail = "ont";			      break;		    case 'n': last_cmd = CMD_NEXT;			      tail = "ext";			      break;		    case 's': last_cmd = CMD_STEP;			      tail = "tep";			      break;		    case 'f': last_cmd = CMD_FINISH;			      tail = "inish";			      break;		    case 'q': last_cmd = CMD_QUIT;			      tail = "uit";			      break;		    case 'i': last_cmd = CMD_INTERRUPT;			      tail = "nterrupt";			      break;		    default: last_cmd = 0;		}		if (last_cmd != 0)		{		    /* Check that the tail matches. */		    ++p;		    while (*p != NUL && *p == *tail)		    {			++p;			++tail;		    }		    if (ASCII_ISALPHA(*p))			last_cmd = 0;		}	    } 	    if (last_cmd != 0)	    {		/* Execute debug command: decided where to break next and		 * return. */		switch (last_cmd)		{		    case CMD_CONT:			debug_break_level = -1;			break;		    case CMD_NEXT:			debug_break_level = ex_nesting_level;			break;		    case CMD_STEP:			debug_break_level = 9999;			break;		    case CMD_FINISH:			debug_break_level = ex_nesting_level - 1;			break;		    case CMD_QUIT:			got_int = TRUE;			debug_break_level = -1;			break;		    case CMD_INTERRUPT:			got_int = TRUE;			debug_break_level = 9999;			/* Do not repeat ">interrupt" cmd, continue stepping. */			last_cmd = CMD_STEP;			break;		}		break;	    } 	    /* don't debug this command */	    n = debug_break_level;	    debug_break_level = -1;	    (void)do_cmdline(cmdline, getexline, NULL,						DOCMD_VERBOSE|DOCMD_EXCRESET);	    debug_break_level = n; 	    vim_free(cmdline);	}	lines_left = Rows - 1;    }    vim_free(cmdline);     --RedrawingDisabled;    --no_wait_return;    redraw_all_later(NOT_VALID);    need_wait_return = FALSE;    msg_scroll = save_msg_scroll;    lines_left = Rows - 1;    State = save_State;    did_emsg = save_did_emsg;    cmd_silent = save_cmd_silent;    msg_silent = save_msg_silent;    emsg_silent = save_emsg_silent;    redir_off = save_redir_off;     /* Only print the message again when typing a command before coming back     * here. */    debug_did_msg = TRUE;} /* * ":debug". */    voidex_debug(eap)    exarg_T	*eap;{    int		debug_break_level_save = debug_break_level;     debug_break_level = 9999;    do_cmdline_cmd(eap->arg);    debug_break_level = debug_break_level_save;} static char_u	*debug_breakpoint_name = NULL;static linenr_T	debug_breakpoint_lnum; /* * When debugging or a breakpoint is set on a skipped command, no debug prompt * is shown by do_one_cmd().  This situation is indicated by debug_skipped, and * debug_skipped_name is then set to the source name in the breakpoint case.  If * a skipped command decides itself that a debug prompt should be displayed, it * can do so by calling dbg_check_skipped(). */static int	debug_skipped;static char_u	*debug_skipped_name; /* * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is * at or below the break level.  But only when the line is actually * executed.  Return TRUE and set breakpoint_name for skipped commands that * decide to execute something themselves. * Called from do_one_cmd() before executing a command. */    voiddbg_check_breakpoint(eap)    exarg_T	*eap;{    char_u	*p;     debug_skipped = FALSE;    if (debug_breakpoint_name != NULL)    {	if (!eap->skip)	{	    /* replace K_SNR with "<SNR>" */	    if (debug_breakpoint_name[0] == K_SPECIAL		    && debug_breakpoint_name[1] == KS_EXTRA		    && debug_breakpoint_name[2] == (int)KE_SNR)		p = (char_u *)"<SNR>";	    else		p = (char_u *)"";	    smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),		    p,		    debug_breakpoint_name + (*p == NUL ? 0 : 3),		    (long)debug_breakpoint_lnum);	    debug_breakpoint_name = NULL;	    do_debug(eap->cmd);	}	else	{	    debug_skipped = TRUE;	    debug_skipped_name = debug_breakpoint_name;	    debug_breakpoint_name = NULL;	}    }    else if (ex_nesting_level <= debug_break_level)    {	if (!eap->skip)	    do_debug(eap->cmd);	else	{	    debug_skipped = TRUE;	    debug_skipped_name = NULL;	}    }} /* * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was * set.  Return TRUE when the debug mode is entered this time. */    intdbg_check_skipped(eap)    exarg_T	*eap;{    int		prev_got_int;     if (debug_skipped)    {	/*	 * Save the value of got_int and reset it.  We don't want a previous	 * interruption cause flushing the input buffer.	 */	prev_got_int = got_int;	got_int = FALSE;	debug_breakpoint_name = debug_skipped_name;	/* eap->skip is TRUE */	eap->skip = FALSE;	(void)dbg_check_breakpoint(eap);	eap->skip = TRUE;	got_int |= prev_got_int;	return TRUE;    }    return FALSE;} /* * The list of breakpoints: dbg_breakp. * This is a grow-array of structs. */struct debuggy{    int		dbg_nr;		/* breakpoint number */    int		dbg_type;	/* DBG_FUNC or DBG_FILE */    char_u	*dbg_name;	/* function or file name */    regprog_T	*dbg_prog;	/* regexp program */    linenr_T	dbg_lnum;	/* line number in function or file */    int		dbg_forceit;	/* ! used */}; static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};#define BREAKP(idx)		(((struct debuggy *)dbg_breakp.ga_data)[idx])#define DEBUGGY(gap, idx)	(((struct debuggy *)gap->ga_data)[idx])static int last_breakp = 0;	/* nr of last defined breakpoint */ #ifdef FEAT_PROFILE/* Profiling uses file and func names similar to breakpoints. */static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};#endif#define DBG_FUNC	1#define DBG_FILE	2 static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp)); /* * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them * in the entry just after the last one in dbg_breakp.  Note that "dbg_name" * is allocated. * Returns FAIL for failure. */    static intdbg_parsearg(arg, gap)    char_u	*arg;    garray_T	*gap;	    /* either &dbg_breakp or &prof_ga */{    char_u	*p = arg;    char_u	*q;    struct debuggy *bp;    int		here = FALSE;     if (ga_grow(gap, 1) == FAIL)	return FAIL;    bp = &DEBUGGY(gap, gap->ga_len);     /* Find "func" or "file". */    if (STRNCMP(p, "func", 4) == 0)	bp->dbg_type = DBG_FUNC;    else if (STRNCMP(p, "file", 4) == 0)	bp->dbg_type = DBG_FILE;    else if (#ifdef FEAT_PROFILE	    gap != &prof_ga &&#endif	    STRNCMP(p, "here", 4) == 0)    {	if (curbuf->b_ffname == NULL)	{	    EMSG(_(e_noname));	    return FAIL;	}	bp->dbg_type = DBG_FILE;	here = TRUE;    }    else    {	EMSG2(_(e_invarg2), p);	return FAIL;    }    p = skipwhite(p + 4);     /* Find optional line number. */    if (here)	bp->dbg_lnum = curwin->w_cursor.lnum;    else if (#ifdef FEAT_PROFILE	    gap != &prof_ga &&#endif	    VIM_ISDIGIT(*p))    {	bp->dbg_lnum = getdigits(&p);	p = skipwhite(p);    }    else	bp->dbg_lnum = 0;     /* Find the function or file name.  Don't accept a function name with (). */    if ((!here && *p == NUL)	    || (here && *p != NUL)	    || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))    {	EMSG2(_(e_invarg2), arg);	return FAIL;    }     if (bp->dbg_type == DBG_FUNC)	bp->dbg_name = vim_strsave(p);    else if (here)	bp->dbg_name = vim_strsave(curbuf->b_ffname);    else    {	/* Expand the file name in the same way as do_source().  This means	 * doing it twice, so that $DIR/file gets expanded when $DIR is	 * "~/dir". */

Lines 1–500 of 4049.