Newer
Older
/* 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
*/
#include "vim.h"
#include "version.h"
static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
/* 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
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 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 */
# 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 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)])
# 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.
*/
void
do_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;
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# 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);
/*
* 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. Set ignore_script to avoid reading from script input. */
# ifdef FEAT_EX_EXTRA
save_ex_normal_busy = ex_normal_busy;
ex_normal_busy = 0;
# endif
if (!debug_greedy)
typeahead_saved = TRUE;
save_ignore_script = ignore_script;
ignore_script = TRUE;
}
cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# 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".
*/
void
ex_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.
*/
void
dbg_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,
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
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.
*/
int
dbg_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 */
};
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 int
garray_T *gap; /* either &dbg_breakp or &prof_ga */
{
char_u *p = arg;
char_u *q;
struct debuggy *bp;
/* 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". */
q = expand_env_save(p);
if (q == NULL)
return FAIL;
p = expand_env_save(q);
vim_free(q);
if (p == NULL)
return FAIL;
if (*p != '*')
{
bp->dbg_name = fix_fname(p);
vim_free(p);
}
else
bp->dbg_name = p;
}
if (bp->dbg_name == NULL)
return FAIL;
return OK;
}
/*
* ":breakadd".
*/
void
ex_breakadd(eap)
exarg_T *eap;
{
struct debuggy *bp;
char_u *pat;
gap = &dbg_breakp;
#ifdef FEAT_PROFILE
if (eap->cmdidx == CMD_profile)
gap = &prof_ga;
#endif
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);
vim_free(pat);
}
if (pat == NULL || bp->dbg_prog == NULL)
vim_free(bp->dbg_name);
else
{
if (bp->dbg_lnum == 0) /* default line number is 1 */
bp->dbg_lnum = 1;
#ifdef FEAT_PROFILE
if (eap->cmdidx != CMD_profile)
#endif
{
DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
++debug_tick;
}
++gap->ga_len;
}
}
}
/*
* ":debuggreedy".
*/
void
ex_debuggreedy(eap)
exarg_T *eap;
{
if (eap->addr_count == 0 || eap->line2 != 0)
debug_greedy = TRUE;
else
debug_greedy = FALSE;
}
/*
*/
void
ex_breakdel(eap)
exarg_T *eap;
{
struct debuggy *bp, *bpi;
int nr;
int todel = -1;
garray_T *gap;
gap = &dbg_breakp;
#ifdef FEAT_PROFILE
if (eap->cmdidx == CMD_profdel)
gap = &prof_ga;
#endif
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)
else if (*eap->arg == '*')
{
todel = 0;
del_all = TRUE;
}
else
{
/* ":breakdel {func|file} [lnum] {name}" */
bp = &DEBUGGY(gap, gap->ga_len);
for (i = 0; i < gap->ga_len; ++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;
}
}
vim_free(bp->dbg_name);
}
if (todel < 0)
EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
else
vim_free(DEBUGGY(gap, todel).dbg_name);
vim_free(DEBUGGY(gap, todel).dbg_prog);
--gap->ga_len;
if (todel < gap->ga_len)
mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
(gap->ga_len - todel) * sizeof(struct debuggy));
#ifdef FEAT_PROFILE
if (eap->cmdidx == CMD_breakdel)
#endif
++debug_tick;
/* If all breakpoints were removed clear the array. */
if (gap->ga_len == 0)
ga_clear(gap);
}
}
/*
* ":breaklist".
*/
void
ex_breaklist(eap)
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
{
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);
smsg((char_u *)_("%3d %s %s line %ld"),
bp->dbg_nr,
bp->dbg_type == DBG_FUNC ? "func" : "file",
bp->dbg_name,
(long)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(file, fname, after)
int file; /* TRUE for a file, FALSE for a function */
char_u *fname; /* file or function name */
linenr_T after; /* after this line number */
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
{
return debuggy_find(file, fname, after, &dbg_breakp, NULL);
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Return TRUE if profiling is on for a function or sourced file.
*/
int
has_profiling(file, fname, fp)
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);
}
#endif
/*
* Common code for dbg_find_breakpoint() and has_profiling().
*/
static linenr_T
debuggy_find(file, fname, after, gap, fp)
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 = alloc((unsigned)STRLEN(fname) + 3);
if (name == NULL)
name = fname;
else
{
STRCPY(name, "<SNR>");
STRCPY(name + 5, fname + 3);
}
}
/* 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 && (
#ifdef FEAT_PROFILE
gap == &prof_ga ||
#endif
(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))
if (fp != NULL)
*fp = bp->dbg_forceit;
}
got_int |= prev_got_int;
}
}
if (name != fname)
vim_free(name);
return lnum;
}
/*
* Called when a breakpoint was encountered.
*/
void
dbg_breakpoint(name, lnum)
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;
}
# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
/*
* Store the current time in "tm".
*/
void
profile_start(tm)
proftime_T *tm;
{
# ifdef WIN3264
QueryPerformanceCounter(tm);
# else
}
/*
* Compute the elapsed time from "tm" till now and store in "tm".
*/
void
profile_end(tm)
proftime_T *tm;
{
proftime_T now;
# ifdef WIN3264
QueryPerformanceCounter(&now);
tm->QuadPart = now.QuadPart - tm->QuadPart;
# else
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;
{
# ifdef WIN3264
tm->QuadPart -= tm2->QuadPart;
# else
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];
# ifdef WIN3264
LARGE_INTEGER fr;
QueryPerformanceFrequency(&fr);
sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
# else
sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
/*
* 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
{
# ifdef WIN3264
LARGE_INTEGER fr;
QueryPerformanceCounter(tm);
QueryPerformanceFrequency(&fr);
tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
# else
long usec;
gettimeofday(tm, NULL);
usec = (long)tm->tv_usec + (long)msec * 1000;
tm->tv_usec = usec % 1000000L;
tm->tv_sec += usec / 1000000L;
# endif
}
}
* Return TRUE if the current time is past "tm".
int
profile_passed_limit(tm)
proftime_T *tm;
{
proftime_T now;
# ifdef WIN3264
if (tm->QuadPart == 0) /* timer was not set */
return FALSE;
QueryPerformanceCounter(&now);
return (now.QuadPart > tm->QuadPart);
# else
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));
# endif
}
/*
* Set the time in "tm" to zero.
*/
void
profile_zero(tm)
proftime_T *tm;
{
# ifdef WIN3264
tm->QuadPart = 0;
# else
tm->tv_usec = 0;
tm->tv_sec = 0;
# endif
}
# endif /* FEAT_PROFILE || FEAT_RELTIME */
# if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Functions for profiling.
*/
static void script_do_profile __ARGS((scriptitem_T *si));
static void script_dump_profile __ARGS((FILE *fd));
static proftime_T prof_wait_time;
/*
* Add the time "tm2" to "tm".
*/
void
profile_add(tm, tm2)
proftime_T *tm, *tm2;
{
# ifdef WIN3264
tm->QuadPart += tm2->QuadPart;
# else
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. */
#ifdef WIN3264
if (total->QuadPart <= children->QuadPart)
return;
#else
if (total->tv_sec < children->tv_sec
|| (total->tv_sec == children->tv_sec
&& total->tv_usec <= children->tv_usec))
return;
#endif
profile_add(self, total);