diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/ex_cmds2.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/ex_cmds2.c')
| -rw-r--r-- | src/ex_cmds2.c | 3541 |
1 files changed, 0 insertions, 3541 deletions
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c deleted file mode 100644 index 0837e5386e..0000000000 --- a/src/ex_cmds2.c +++ /dev/null @@ -1,3541 +0,0 @@ -/* - * 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 - */ - -#include <string.h> - -#include "vim.h" -#include "version_defs.h" -#include "ex_cmds2.h" -#include "buffer.h" -#include "charset.h" -#include "eval.h" -#include "ex_cmds.h" -#include "ex_docmd.h" -#include "ex_eval.h" -#include "ex_getln.h" -#include "fileio.h" -#include "getchar.h" -#include "mark.h" -#include "mbyte.h" -#include "message.h" -#include "misc1.h" -#include "misc2.h" -#include "garray.h" -#include "memory.h" -#include "move.h" -#include "normal.h" -#include "option.h" -#include "os_unix.h" -#include "path.h" -#include "quickfix.h" -#include "regexp.h" -#include "screen.h" -#include "term.h" -#include "undo.h" -#include "window.h" -#include "os/os.h" -#include "os/shell.h" - -static void cmd_source(char_u *fname, exarg_T *eap); - -/* Growarray to store info about already sourced scripts. - * 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; - int sn_dev_valid; - uint64_t sn_dev; - uint64_t sn_ino; - 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 spent in script + children */ - proftime_T sn_pr_self; /* time spent 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 */ -} 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]) - -/* 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 spent in a line + children */ - proftime_T sn_prl_self; /* time spent in a line itself */ -} sn_prl_T; - -# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)]) - -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. - */ -void do_debug(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; - int typeahead_saved = FALSE; - int save_ignore_script = 0; - int save_ex_normal_busy; - 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 - - - /* 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; - - 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 %" PRId64 ": %s"), (int64_t)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; - /* 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. Set ignore_script to avoid reading from script input. */ - save_ex_normal_busy = ex_normal_busy; - ex_normal_busy = 0; - if (!debug_greedy) { - save_typeahead(&typeaheadbuf); - typeahead_saved = TRUE; - save_ignore_script = ignore_script; - ignore_script = TRUE; - } - - cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL); - - if (typeahead_saved) { - restore_typeahead(&typeaheadbuf); - ignore_script = save_ignore_script; - } - ex_normal_busy = save_ex_normal_busy; - - 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; - - free(cmdline); - } - lines_left = Rows - 1; - } - 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". - */ -void ex_debug(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. - */ -void dbg_check_breakpoint(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 %" PRId64), - p, - debug_breakpoint_name + (*p == NUL ? 0 : 3), - (int64_t)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. - */ -int dbg_check_skipped(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 */ - -/* Profiling uses file and func names similar to breakpoints. */ -static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL}; -#define DBG_FUNC 1 -#define DBG_FILE 2 - -static int dbg_parsearg(char_u *arg, garray_T *gap); -static linenr_T debuggy_find(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 int -dbg_parsearg ( - 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; - - ga_grow(gap, 1); - - 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 ( - gap != &prof_ga && - 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 ( - gap != &prof_ga && - 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". */ - q = expand_env_save(p); - if (q == NULL) - return FAIL; - p = expand_env_save(q); - free(q); - if (p == NULL) - return FAIL; - if (*p != '*') { - bp->dbg_name = fix_fname(p); - free(p); - } else - bp->dbg_name = p; - } - - if (bp->dbg_name == NULL) - return FAIL; - return OK; -} - -/* - * ":breakadd". - */ -void ex_breakadd(exarg_T *eap) -{ - struct debuggy *bp; - char_u *pat; - garray_T *gap; - - gap = &dbg_breakp; - if (eap->cmdidx == CMD_profile) - gap = &prof_ga; - - if (dbg_parsearg(eap->arg, gap) == OK) { - bp = &DEBUGGY(gap, gap->ga_len); - bp->dbg_forceit = eap->forceit; - - pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE); - if (pat != NULL) { - bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); - free(pat); - } - if (pat == NULL || bp->dbg_prog == NULL) - free(bp->dbg_name); - else { - if (bp->dbg_lnum == 0) /* default line number is 1 */ - bp->dbg_lnum = 1; - if (eap->cmdidx != CMD_profile) { - DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; - ++debug_tick; - } - ++gap->ga_len; - } - } -} - -/* - * ":debuggreedy". - */ -void ex_debuggreedy(exarg_T *eap) -{ - if (eap->addr_count == 0 || eap->line2 != 0) - debug_greedy = TRUE; - else - debug_greedy = FALSE; -} - -/* - * ":breakdel" and ":profdel". - */ -void ex_breakdel(exarg_T *eap) -{ - struct debuggy *bp, *bpi; - int nr; - int todel = -1; - int del_all = FALSE; - int i; - linenr_T best_lnum = 0; - garray_T *gap; - - gap = &dbg_breakp; - if (eap->cmdidx == CMD_profdel) { - gap = &prof_ga; - } - - if (vim_isdigit(*eap->arg)) { - /* ":breakdel {nr}" */ - nr = atol((char *)eap->arg); - for (i = 0; i < gap->ga_len; ++i) - if (DEBUGGY(gap, i).dbg_nr == nr) { - todel = i; - break; - } - } else if (*eap->arg == '*') { - todel = 0; - del_all = TRUE; - } else { - /* ":breakdel {func|file} [lnum] {name}" */ - if (dbg_parsearg(eap->arg, gap) == FAIL) - return; - bp = &DEBUGGY(gap, gap->ga_len); - for (i = 0; i < gap->ga_len; ++i) { - bpi = &DEBUGGY(gap, i); - if (bp->dbg_type == bpi->dbg_type - && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 - && (bp->dbg_lnum == bpi->dbg_lnum - || (bp->dbg_lnum == 0 - && (best_lnum == 0 - || bpi->dbg_lnum < best_lnum)))) { - todel = i; - best_lnum = bpi->dbg_lnum; - } - } - free(bp->dbg_name); - } - - if (todel < 0) - EMSG2(_("E161: Breakpoint not found: %s"), eap->arg); - else { - while (gap->ga_len > 0) { - free(DEBUGGY(gap, todel).dbg_name); - vim_regfree(DEBUGGY(gap, todel).dbg_prog); - --gap->ga_len; - if (todel < gap->ga_len) - memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), - (gap->ga_len - todel) * sizeof(struct debuggy)); - if (eap->cmdidx == CMD_breakdel) - ++debug_tick; - if (!del_all) - break; - } - - /* If all breakpoints were removed clear the array. */ - if (gap->ga_len == 0) - ga_clear(gap); - } -} - -/* - * ":breaklist". - */ -void ex_breaklist(exarg_T *eap) -{ - struct debuggy *bp; - int i; - - if (dbg_breakp.ga_len == 0) - MSG(_("No breakpoints defined")); - else - for (i = 0; i < dbg_breakp.ga_len; ++i) { - bp = &BREAKP(i); - if (bp->dbg_type == DBG_FILE) - home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE); - smsg((char_u *)_("%3d %s %s line %" PRId64), - bp->dbg_nr, - bp->dbg_type == DBG_FUNC ? "func" : "file", - bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, - (int64_t)bp->dbg_lnum); - } -} - -/* - * Find a breakpoint for a function or sourced file. - * Returns line number at which to break; zero when no matching breakpoint. - */ -linenr_T -dbg_find_breakpoint ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - linenr_T after /* after this line number */ -) -{ - return debuggy_find(file, fname, after, &dbg_breakp, NULL); -} - -/* - * Return TRUE if profiling is on for a function or sourced file. - */ -int -has_profiling ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - int *fp /* return: forceit */ -) -{ - return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) - != (linenr_T)0; -} - -/* - * Common code for dbg_find_breakpoint() and has_profiling(). - */ -static linenr_T -debuggy_find ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - linenr_T after, /* after this line number */ - garray_T *gap, /* either &dbg_breakp or &prof_ga */ - int *fp /* if not NULL: return forceit */ -) -{ - struct debuggy *bp; - int i; - linenr_T lnum = 0; - regmatch_T regmatch; - char_u *name = fname; - int prev_got_int; - - /* Return quickly when there are no breakpoints. */ - if (gap->ga_len == 0) - return (linenr_T)0; - - /* Replace K_SNR in function name with "<SNR>". */ - if (!file && fname[0] == K_SPECIAL) { - name = xmalloc(STRLEN(fname) + 3); - STRCPY(name, "<SNR>"); - STRCPY(name + 5, fname + 3); - } - - for (i = 0; i < gap->ga_len; ++i) { - /* Skip entries that are not useful or are for a line that is beyond - * an already found breakpoint. */ - bp = &DEBUGGY(gap, i); - if (((bp->dbg_type == DBG_FILE) == file && ( - gap == &prof_ga || - (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum))))) { - regmatch.regprog = bp->dbg_prog; - regmatch.rm_ic = FALSE; - /* - * Save the value of got_int and reset it. We don't want a - * previous interruption cancel matching, only hitting CTRL-C - * while matching should abort it. - */ - prev_got_int = got_int; - got_int = FALSE; - if (vim_regexec(®match, name, (colnr_T)0)) { - lnum = bp->dbg_lnum; - if (fp != NULL) - *fp = bp->dbg_forceit; - } - got_int |= prev_got_int; - } - } - if (name != fname) - free(name); - - return lnum; -} - -/* - * Called when a breakpoint was encountered. - */ -void dbg_breakpoint(char_u *name, linenr_T lnum) -{ - /* We need to check if this line is actually executed in do_one_cmd() */ - debug_breakpoint_name = name; - debug_breakpoint_lnum = lnum; -} - - -/* - * Store the current time in "tm". - */ -void profile_start(tm) -proftime_T *tm; -{ - gettimeofday(tm, NULL); -} - -/* - * Compute the elapsed time from "tm" till now and store in "tm". - */ -void profile_end(tm) -proftime_T *tm; -{ - proftime_T now; - - gettimeofday(&now, NULL); - tm->tv_usec = now.tv_usec - tm->tv_usec; - tm->tv_sec = now.tv_sec - tm->tv_sec; - if (tm->tv_usec < 0) { - tm->tv_usec += 1000000; - --tm->tv_sec; - } -} - -/* - * Subtract the time "tm2" from "tm". - */ -void profile_sub(tm, tm2) -proftime_T *tm, *tm2; -{ - tm->tv_usec -= tm2->tv_usec; - tm->tv_sec -= tm2->tv_sec; - if (tm->tv_usec < 0) { - tm->tv_usec += 1000000; - --tm->tv_sec; - } -} - -/* - * Return a string that represents the time in "tm". - * Uses a static buffer! - */ -char * profile_msg(tm) -proftime_T *tm; -{ - static char buf[50]; - - sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec); - return buf; -} - -/* - * Put the time "msec" past now in "tm". - */ -void profile_setlimit(msec, tm) -long msec; -proftime_T *tm; -{ - if (msec <= 0) /* no limit */ - profile_zero(tm); - else { - long usec; - - gettimeofday(tm, NULL); - usec = (long)tm->tv_usec + (long)msec * 1000; - tm->tv_usec = usec % 1000000L; - tm->tv_sec += usec / 1000000L; - } -} - -/* - * Return TRUE if the current time is past "tm". - */ -int profile_passed_limit(tm) -proftime_T *tm; -{ - proftime_T now; - - if (tm->tv_sec == 0) /* timer was not set */ - return FALSE; - gettimeofday(&now, NULL); - return now.tv_sec > tm->tv_sec - || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec); -} - -/* - * Set the time in "tm" to zero. - */ -void profile_zero(tm) -proftime_T *tm; -{ - tm->tv_usec = 0; - tm->tv_sec = 0; -} - - -#include <math.h> - -/* - * Divide the time "tm" by "count" and store in "tm2". - */ -void profile_divide(tm, count, tm2) -proftime_T *tm; -proftime_T *tm2; -int count; -{ - if (count == 0) - profile_zero(tm2); - else { - double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count; - - tm2->tv_sec = floor(usec / 1000000.0); - tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0)); - } -} - -/* - * Functions for profiling. - */ -static void script_do_profile(scriptitem_T *si); -static void script_dump_profile(FILE *fd); -static proftime_T prof_wait_time; - -/* - * Add the time "tm2" to "tm". - */ -void profile_add(tm, tm2) -proftime_T *tm, *tm2; -{ - tm->tv_usec += tm2->tv_usec; - tm->tv_sec += tm2->tv_sec; - if (tm->tv_usec >= 1000000) { - tm->tv_usec -= 1000000; - ++tm->tv_sec; - } -} - -/* - * Add the "self" time from the total time and the children's time. - */ -void profile_self(self, total, children) -proftime_T *self, *total, *children; -{ - /* Check that the result won't be negative. Can happen with recursive - * calls. */ - if (total->tv_sec < children->tv_sec - || (total->tv_sec == children->tv_sec - && total->tv_usec <= children->tv_usec)) - return; - profile_add(self, total); - profile_sub(self, children); -} - -/* - * Get the current waittime. - */ -void profile_get_wait(tm) -proftime_T *tm; -{ - *tm = prof_wait_time; -} - -/* - * Subtract the passed waittime since "tm" from "tma". - */ -void profile_sub_wait(tm, tma) -proftime_T *tm, *tma; -{ - proftime_T tm3 = prof_wait_time; - - profile_sub(&tm3, tm); - profile_sub(tma, &tm3); -} - -/* - * Return TRUE if "tm1" and "tm2" are equal. - */ -int profile_equal(tm1, tm2) -proftime_T *tm1, *tm2; -{ - return tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec; -} - -/* - * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2" - */ -int profile_cmp(tm1, tm2) -const proftime_T *tm1, *tm2; -{ - if (tm1->tv_sec == tm2->tv_sec) - return tm2->tv_usec - tm1->tv_usec; - return tm2->tv_sec - tm1->tv_sec; -} - -static char_u *profile_fname = NULL; -static proftime_T pause_time; - -/* - * ":profile cmd args" - */ -void ex_profile(exarg_T *eap) -{ - char_u *e; - int len; - - e = skiptowhite(eap->arg); - len = (int)(e - eap->arg); - e = skipwhite(e); - - if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL) { - free(profile_fname); - profile_fname = vim_strsave(e); - do_profiling = PROF_YES; - profile_zero(&prof_wait_time); - set_vim_var_nr(VV_PROFILING, 1L); - } else if (do_profiling == PROF_NONE) - EMSG(_("E750: First use \":profile start {fname}\"")); - else if (STRCMP(eap->arg, "pause") == 0) { - if (do_profiling == PROF_YES) - profile_start(&pause_time); - do_profiling = PROF_PAUSED; - } else if (STRCMP(eap->arg, "continue") == 0) { - if (do_profiling == PROF_PAUSED) { - profile_end(&pause_time); - profile_add(&prof_wait_time, &pause_time); - } - do_profiling = PROF_YES; - } else { - /* The rest is similar to ":breakadd". */ - ex_breakadd(eap); - } -} - -/* Command line expansion for :profile. */ -static enum { - PEXP_SUBCMD, /* expand :profile sub-commands */ - PEXP_FUNC /* expand :profile func {funcname} */ -} pexpand_what; - -static char *pexpand_cmds[] = { - "start", -#define PROFCMD_START 0 - "pause", -#define PROFCMD_PAUSE 1 - "continue", -#define PROFCMD_CONTINUE 2 - "func", -#define PROFCMD_FUNC 3 - "file", -#define PROFCMD_FILE 4 - NULL -#define PROFCMD_LAST 5 -}; - -/* - * Function given to ExpandGeneric() to obtain the profile command - * specific expansion. - */ -char_u *get_profile_name(expand_T *xp, int idx) -{ - switch (pexpand_what) { - case PEXP_SUBCMD: - return (char_u *)pexpand_cmds[idx]; - /* case PEXP_FUNC: TODO */ - default: - return NULL; - } -} - -/* - * Handle command line completion for :profile command. - */ -void set_context_in_profile_cmd(expand_T *xp, char_u *arg) -{ - char_u *end_subcmd; - - /* Default: expand subcommands. */ - xp->xp_context = EXPAND_PROFILE; - pexpand_what = PEXP_SUBCMD; - xp->xp_pattern = arg; - - end_subcmd = skiptowhite(arg); - if (*end_subcmd == NUL) - return; - - if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) { - xp->xp_context = EXPAND_FILES; - xp->xp_pattern = skipwhite(end_subcmd); - return; - } - - /* TODO: expand function names after "func" */ - xp->xp_context = EXPAND_NOTHING; -} - -/* - * Dump the profiling info. - */ -void profile_dump(void) -{ - FILE *fd; - - if (profile_fname != NULL) { - fd = mch_fopen((char *)profile_fname, "w"); - if (fd == NULL) - EMSG2(_(e_notopen), profile_fname); - else { - script_dump_profile(fd); - func_dump_profile(fd); - fclose(fd); - } - } -} - -/* - * Start profiling script "fp". - */ -static void script_do_profile(scriptitem_T *si) -{ - si->sn_pr_count = 0; - profile_zero(&si->sn_pr_total); - profile_zero(&si->sn_pr_self); - - ga_init(&si->sn_prl_ga, sizeof(sn_prl_T), 100); - si->sn_prl_idx = -1; - si->sn_prof_on = TRUE; - si->sn_pr_nest = 0; -} - -/* - * save time when starting to invoke another script or function. - */ -void script_prof_save(tm) -proftime_T *tm; /* place to store wait time */ -{ - scriptitem_T *si; - - if (current_SID > 0 && current_SID <= script_items.ga_len) { - si = &SCRIPT_ITEM(current_SID); - if (si->sn_prof_on && si->sn_pr_nest++ == 0) - profile_start(&si->sn_pr_child); - } - profile_get_wait(tm); -} - -/* - * Count time spent in children after invoking another script or function. - */ -void script_prof_restore(tm) -proftime_T *tm; -{ - scriptitem_T *si; - - if (current_SID > 0 && current_SID <= script_items.ga_len) { - si = &SCRIPT_ITEM(current_SID); - if (si->sn_prof_on && --si->sn_pr_nest == 0) { - profile_end(&si->sn_pr_child); - profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */ - profile_add(&si->sn_pr_children, &si->sn_pr_child); - profile_add(&si->sn_prl_children, &si->sn_pr_child); - } - } -} - -static proftime_T inchar_time; - -/* - * Called when starting to wait for the user to type a character. - */ -void prof_inchar_enter(void) -{ - profile_start(&inchar_time); -} - -/* - * Called when finished waiting for the user to type a character. - */ -void prof_inchar_exit(void) -{ - profile_end(&inchar_time); - profile_add(&prof_wait_time, &inchar_time); -} - -/* - * Dump the profiling results for all scripts in file "fd". - */ -static void script_dump_profile(FILE *fd) -{ - int id; - scriptitem_T *si; - int i; - FILE *sfd; - sn_prl_T *pp; - - for (id = 1; id <= script_items.ga_len; ++id) { - si = &SCRIPT_ITEM(id); - if (si->sn_prof_on) { - fprintf(fd, "SCRIPT %s\n", si->sn_name); - if (si->sn_pr_count == 1) - fprintf(fd, "Sourced 1 time\n"); - else - fprintf(fd, "Sourced %d times\n", si->sn_pr_count); - fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total)); - fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self)); - fprintf(fd, "\n"); - fprintf(fd, "count total (s) self (s)\n"); - - sfd = mch_fopen((char *)si->sn_name, "r"); - if (sfd == NULL) - fprintf(fd, "Cannot open file!\n"); - else { - for (i = 0; i < si->sn_prl_ga.ga_len; ++i) { - if (vim_fgets(IObuff, IOSIZE, sfd)) - break; - pp = &PRL_ITEM(si, i); - if (pp->snp_count > 0) { - fprintf(fd, "%5d ", pp->snp_count); - if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self)) - fprintf(fd, " "); - else - fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total)); - fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self)); - } else - fprintf(fd, " "); - fprintf(fd, "%s", IObuff); - } - fclose(sfd); - } - fprintf(fd, "\n"); |