aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_eval.c')
-rw-r--r--src/nvim/ex_eval.c196
1 files changed, 105 insertions, 91 deletions
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index f76e60f6c5..d2a1d53b78 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -1,6 +1,3 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
/// @file ex_eval.c
///
/// Functions for Ex command line for the +eval feature.
@@ -11,33 +8,34 @@
#include <stdio.h>
#include <string.h>
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_eval_defs.h"
+#include "nvim/func_attr.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/option_defs.h"
-#include "nvim/pos.h"
+#include "nvim/option_vars.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h"
#endif
+static const char e_multiple_else[] = N_("E583: Multiple :else");
+static const char e_multiple_finally[] = N_("E607: Multiple :finally");
+
// Exception handling terms:
//
// :try ":try" command ─┐
@@ -154,11 +152,10 @@ int aborted_in_try(void)
/// When several messages appear in the same command, the first is usually the
/// most specific one and used as the exception value. The "severe" flag can be
/// set to true, if a later but severer message should be used instead.
-bool cause_errthrow(const char *mesg, bool severe, bool *ignore)
+bool cause_errthrow(const char *mesg, bool multiline, bool severe, bool *ignore)
FUNC_ATTR_NONNULL_ALL
{
msglist_T *elem;
- msglist_T **plist;
// Do nothing when displaying the interrupt message or reporting an
// uncaught exception (which has already been discarded then) at the top
@@ -239,21 +236,20 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore)
// returned. - Throw only the first of several errors in a row, except
// a severe error is following.
if (msg_list != NULL) {
- plist = msg_list;
+ msglist_T **plist = msg_list;
while (*plist != NULL) {
plist = &(*plist)->next;
}
elem = xmalloc(sizeof(msglist_T));
elem->msg = xstrdup(mesg);
+ elem->multiline = multiline;
elem->next = NULL;
elem->throw_msg = NULL;
*plist = elem;
if (plist == msg_list || severe) {
- char *tmsg;
-
// Skip the extra "Vim " prefix for message "E458".
- tmsg = elem->msg;
+ char *tmsg = elem->msg;
if (strncmp(tmsg, "Vim E", 5) == 0
&& ascii_isdigit(tmsg[5])
&& ascii_isdigit(tmsg[6])
@@ -278,11 +274,9 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore)
/// Free a "msg_list" and the messages it contains.
static void free_msglist(msglist_T *l)
{
- msglist_T *messages, *next;
-
- messages = l;
+ msglist_T *messages = l;
while (messages != NULL) {
- next = messages->next;
+ msglist_T *next = messages->next;
xfree(messages->msg);
xfree(messages->sfile);
xfree(messages);
@@ -378,12 +372,12 @@ int do_intthrow(cstack_T *cstack)
/// Get an exception message that is to be stored in current_exception->value.
char *get_exception_string(void *value, except_type_T type, char *cmdname, int *should_free)
{
- char *ret, *mesg;
- char *p, *val;
+ char *ret;
if (type == ET_ERROR) {
+ char *val;
*should_free = true;
- mesg = ((msglist_T *)value)->throw_msg;
+ char *mesg = ((msglist_T *)value)->throw_msg;
if (cmdname != NULL && *cmdname != NUL) {
size_t cmdlen = strlen(cmdname);
ret = xstrnsave("Vim(", 4 + cmdlen + 2 + strlen(mesg));
@@ -398,7 +392,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int *
// msg_add_fname may have been used to prefix the message with a file
// name in quotes. In the exception value, put the file name in
// parentheses and move it to the end.
- for (p = mesg;; p++) {
+ for (char *p = mesg;; p++) {
if (*p == NUL
|| (*p == 'E'
&& ascii_isdigit(p[1])
@@ -441,9 +435,6 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int *
/// exception.
static int throw_exception(void *value, except_type_T type, char *cmdname)
{
- except_T *excp;
- int should_free;
-
// Disallow faking Interrupt or error exceptions as user exceptions. They
// would be treated differently from real interrupt or error exceptions
// when no active try block is found, see do_cmdline().
@@ -456,7 +447,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
}
}
- excp = xmalloc(sizeof(except_T));
+ except_T *excp = xmalloc(sizeof(except_T));
if (type == ET_ERROR) {
// Store the original message and prefix the exception value with
@@ -464,6 +455,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
excp->messages = (msglist_T *)value;
}
+ int should_free;
excp->value = get_exception_string(value, type, cmdname, &should_free);
if (excp->value == NULL && should_free) {
goto nomem;
@@ -495,7 +487,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
if (debug_break_level > 0 || *p_vfile == NUL) {
msg_scroll = true; // always scroll up, don't overwrite
}
- smsg(_("Exception thrown: %s"), excp->value);
+ smsg(0, _("Exception thrown: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
if (debug_break_level > 0 || *p_vfile == NUL) {
@@ -525,8 +517,6 @@ fail:
/// caught and the catch clause has been ended normally.
static void discard_exception(except_T *excp, bool was_finished)
{
- char *saved_IObuff;
-
if (current_exception == excp) {
current_exception = NULL;
}
@@ -538,7 +528,7 @@ static void discard_exception(except_T *excp, bool was_finished)
if (p_verbose >= 13 || debug_break_level > 0) {
int save_msg_silent = msg_silent;
- saved_IObuff = xstrdup(IObuff);
+ char *saved_IObuff = xstrdup(IObuff);
if (debug_break_level > 0) {
msg_silent = false; // display messages
} else {
@@ -548,7 +538,7 @@ static void discard_exception(except_T *excp, bool was_finished)
if (debug_break_level > 0 || *p_vfile == NUL) {
msg_scroll = true; // always scroll up, don't overwrite
}
- smsg(was_finished ? _("Exception finished: %s") : _("Exception discarded: %s"), excp->value);
+ smsg(0, was_finished ? _("Exception finished: %s") : _("Exception discarded: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
if (debug_break_level > 0 || *p_vfile == NUL) {
cmdline_row = msg_row;
@@ -615,7 +605,7 @@ static void catch_exception(except_T *excp)
if (debug_break_level > 0 || *p_vfile == NUL) {
msg_scroll = true; // always scroll up, don't overwrite
}
- smsg(_("Exception caught: %s"), excp->value);
+ smsg(0, _("Exception caught: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
if (debug_break_level > 0 || *p_vfile == NUL) {
@@ -663,6 +653,40 @@ static void finish_exception(except_T *excp)
discard_exception(excp, true);
}
+/// Save the current exception state in "estate"
+void exception_state_save(exception_state_T *estate)
+{
+ estate->estate_current_exception = current_exception;
+ estate->estate_did_throw = did_throw;
+ estate->estate_need_rethrow = need_rethrow;
+ estate->estate_trylevel = trylevel;
+ estate->estate_did_emsg = did_emsg;
+}
+
+/// Restore the current exception state from "estate"
+void exception_state_restore(exception_state_T *estate)
+{
+ // Handle any outstanding exceptions before restoring the state
+ if (did_throw) {
+ handle_did_throw();
+ }
+ current_exception = estate->estate_current_exception;
+ did_throw = estate->estate_did_throw;
+ need_rethrow = estate->estate_need_rethrow;
+ trylevel = estate->estate_trylevel;
+ did_emsg = estate->estate_did_emsg;
+}
+
+/// Clear the current exception state
+void exception_state_clear(void)
+{
+ current_exception = NULL;
+ did_throw = false;
+ need_rethrow = false;
+ trylevel = 0;
+ did_emsg = 0;
+}
+
// Flags specifying the message displayed by report_pending.
#define RP_MAKE 0
#define RP_RESUME 1
@@ -677,7 +701,6 @@ static void report_pending(int action, int pending, void *value)
{
char *mesg;
char *s;
- int save_msg_silent;
assert(value || !(pending & CSTP_THROW));
@@ -727,13 +750,13 @@ static void report_pending(int action, int pending, void *value)
}
}
- save_msg_silent = msg_silent;
+ int save_msg_silent = msg_silent;
if (debug_break_level > 0) {
msg_silent = false; // display messages
}
no_wait_return++;
msg_scroll = true; // always scroll up, don't overwrite
- smsg(mesg, s);
+ smsg(0, mesg, s);
msg_puts("\n"); // don't overwrite this either
cmdline_row = msg_row;
no_wait_return--;
@@ -797,17 +820,20 @@ void report_discard_pending(int pending, void *value)
void ex_eval(exarg_T *eap)
{
typval_T tv;
+ evalarg_T evalarg;
+
+ fill_evalarg_from_eap(&evalarg, eap, eap->skip);
- if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) {
+ if (eval0(eap->arg, &tv, eap, &evalarg) == OK) {
tv_clear(&tv);
}
+
+ clear_evalarg(&evalarg, eap);
}
/// Handle ":if".
void ex_if(exarg_T *eap)
{
- int skip;
- int result;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_idx == CSTACK_LEN - 1) {
@@ -816,10 +842,10 @@ void ex_if(exarg_T *eap)
cstack->cs_idx++;
cstack->cs_flags[cstack->cs_idx] = 0;
- skip = CHECK_SKIP;
+ int skip = CHECK_SKIP;
bool error;
- result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ int result = eval_to_bool(eap->arg, &error, eap, skip);
if (!skip && !error) {
if (result) {
@@ -860,7 +886,6 @@ void ex_endif(exarg_T *eap)
/// Handle ":else" and ":elseif".
void ex_else(exarg_T *eap)
{
- bool result = false;
cstack_T *const cstack = eap->cstack;
bool skip = CHECK_SKIP;
@@ -876,7 +901,7 @@ void ex_else(exarg_T *eap)
skip = true;
} else if (cstack->cs_flags[cstack->cs_idx] & CSF_ELSE) {
if (eap->cmdidx == CMD_else) {
- eap->errmsg = _("E583: multiple :else");
+ eap->errmsg = _(e_multiple_else);
return;
}
eap->errmsg = _("E584: :elseif after :else");
@@ -907,6 +932,7 @@ void ex_else(exarg_T *eap)
}
if (eap->cmdidx == CMD_elseif) {
+ bool result = false;
bool error;
// When skipping we ignore most errors, but a missing expression is
// wrong, perhaps it should have been "else".
@@ -914,7 +940,7 @@ void ex_else(exarg_T *eap)
if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) {
semsg(_(e_invexpr2), eap->arg);
} else {
- result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ result = eval_to_bool(eap->arg, &error, eap, skip);
}
// When throwing error exceptions, we want to throw always the first
@@ -941,13 +967,12 @@ void ex_else(exarg_T *eap)
void ex_while(exarg_T *eap)
{
bool error;
- int skip;
- int result;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_idx == CSTACK_LEN - 1) {
eap->errmsg = _("E585: :while/:for nesting too deep");
} else {
+ int result;
// The loop flag is set when we have jumped back from the matching
// ":endwhile" or ":endfor". When not set, need to initialise this
// cstack entry.
@@ -959,14 +984,13 @@ void ex_while(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] =
eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR;
- skip = CHECK_SKIP;
- if (eap->cmdidx == CMD_while) {
- // ":while bool-expr"
- result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
- } else {
+ int skip = CHECK_SKIP;
+ if (eap->cmdidx == CMD_while) { // ":while bool-expr"
+ result = eval_to_bool(eap->arg, &error, eap, skip);
+ } else { // ":for var in list-expr"
+ evalarg_T evalarg;
+ fill_evalarg_from_eap(&evalarg, eap, skip);
void *fi;
-
- // ":for var in list-expr"
if ((cstack->cs_lflags & CSL_HAD_LOOP) != 0) {
// Jumping here from a ":continue" or ":endfor": use the
// previously evaluated list.
@@ -974,7 +998,7 @@ void ex_while(exarg_T *eap)
error = false;
} else {
// Evaluate the argument and get the info in a structure.
- fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip);
+ fi = eval_for_line(eap->arg, &error, eap, &evalarg);
cstack->cs_forinfo[cstack->cs_idx] = fi;
}
@@ -989,6 +1013,7 @@ void ex_while(exarg_T *eap)
free_for_info(fi);
cstack->cs_forinfo[cstack->cs_idx] = NULL;
}
+ clear_evalarg(&evalarg, eap);
}
// If this cstack entry was just initialised and is active, set the
@@ -1013,7 +1038,6 @@ void ex_while(exarg_T *eap)
/// Handle ":continue"
void ex_continue(exarg_T *eap)
{
- int idx;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
@@ -1023,7 +1047,7 @@ void ex_continue(exarg_T *eap)
// conditional not in its finally clause (which is then to be executed
// next). Therefore, deactivate all conditionals except the ":while"
// itself (if reached).
- idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, false);
+ int idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, false);
assert(idx >= 0);
if (cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)) {
rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel);
@@ -1043,7 +1067,6 @@ void ex_continue(exarg_T *eap)
/// Handle ":break"
void ex_break(exarg_T *eap)
{
- int idx;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
@@ -1053,7 +1076,7 @@ void ex_break(exarg_T *eap)
// conditional not in its finally clause (which is then to be
// executed next) is found. In the latter case, make the ":break"
// pending for execution at the ":endtry".
- idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, true);
+ int idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, true);
if (idx >= 0 && !(cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR))) {
cstack->cs_pending[idx] = CSTP_BREAK;
report_make_pending(CSTP_BREAK, NULL);
@@ -1065,10 +1088,8 @@ void ex_break(exarg_T *eap)
void ex_endwhile(exarg_T *eap)
{
cstack_T *const cstack = eap->cstack;
- int idx;
- char *err;
+ const char *err;
int csf;
- int fl;
if (eap->cmdidx == CMD_endwhile) {
err = e_while;
@@ -1081,7 +1102,7 @@ void ex_endwhile(exarg_T *eap)
if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = _(err);
} else {
- fl = cstack->cs_flags[cstack->cs_idx];
+ int fl = cstack->cs_flags[cstack->cs_idx];
if (!(fl & csf)) {
// If we are in a ":while" or ":for" but used the wrong endloop
// command, do not rewind to the next enclosing ":for"/":while".
@@ -1098,6 +1119,7 @@ void ex_endwhile(exarg_T *eap)
eap->errmsg = _(e_endtry);
}
// Try to find the matching ":while" and report what's missing.
+ int idx;
for (idx = cstack->cs_idx; idx > 0; idx--) {
fl = cstack->cs_flags[idx];
if ((fl & CSF_TRY) && !(fl & CSF_FINALLY)) {
@@ -1136,12 +1158,11 @@ void ex_endwhile(exarg_T *eap)
/// Handle ":throw expr"
void ex_throw(exarg_T *eap)
{
- const char *arg = (const char *)eap->arg;
+ char *arg = eap->arg;
char *value;
if (*arg != NUL && *arg != '|' && *arg != '\n') {
- value = eval_to_string_skip(arg, (const char **)&eap->nextcmd,
- (bool)eap->skip);
+ value = eval_to_string_skip(arg, eap, eap->skip);
} else {
emsg(_(e_argreq));
value = NULL;
@@ -1163,10 +1184,8 @@ void ex_throw(exarg_T *eap)
/// used for rethrowing an uncaught exception.
void do_throw(cstack_T *cstack)
{
- int idx;
int inactivate_try = false;
- //
// Cleanup and deactivate up to the next surrounding try conditional that
// is not in its finally clause. Normally, do not deactivate the try
// conditional itself, so that its ACTIVE flag can be tested below. But
@@ -1174,7 +1193,7 @@ void do_throw(cstack_T *cstack)
// deactivate the try conditional, too, as if the conversion had been done,
// and reset the did_emsg or got_int flag, so this won't happen again at
// the next surrounding try conditional.
- //
+
#ifndef THROW_ON_ERROR_TRUE
if (did_emsg && !THROW_ON_ERROR) {
inactivate_try = true;
@@ -1187,7 +1206,7 @@ void do_throw(cstack_T *cstack)
got_int = false;
}
#endif
- idx = cleanup_conditionals(cstack, 0, inactivate_try);
+ int idx = cleanup_conditionals(cstack, 0, inactivate_try);
if (idx >= 0) {
// If this try conditional is active and we are before its first
// ":catch", set THROWN so that the ":catch" commands will check
@@ -1220,7 +1239,6 @@ void do_throw(cstack_T *cstack)
/// Handle ":try"
void ex_try(exarg_T *eap)
{
- int skip;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_idx == CSTACK_LEN - 1) {
@@ -1231,7 +1249,7 @@ void ex_try(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
- skip = CHECK_SKIP;
+ int skip = CHECK_SKIP;
if (!skip) {
// Set ACTIVE and TRUE. TRUE means that the corresponding ":catch"
@@ -1271,12 +1289,9 @@ void ex_catch(exarg_T *eap)
int idx = 0;
bool give_up = false;
bool skip = false;
- bool caught = false;
char *end;
- char save_char = 0;
char *save_cpo;
regmatch_T regmatch;
- int prev_got_int;
cstack_T *const cstack = eap->cstack;
char *pat;
@@ -1319,6 +1334,7 @@ void ex_catch(exarg_T *eap)
}
if (!give_up) {
+ bool caught = false;
// Don't do something when no exception has been thrown or when the
// corresponding try block never got active (because of an inactive
// surrounding conditional or after an error or interrupt or throw).
@@ -1344,6 +1360,7 @@ void ex_catch(exarg_T *eap)
// the original exception, replace it by an interrupt exception,
// and don't catch it in this try block.
if (!dbg_check_skipped(eap) || !do_intthrow(cstack)) {
+ char save_char = 0;
// Terminate the pattern and avoid the 'l' flag in 'cpoptions'
// while compiling it.
if (end != NULL) {
@@ -1351,7 +1368,7 @@ void ex_catch(exarg_T *eap)
*end = NUL;
}
save_cpo = p_cpo;
- p_cpo = empty_option;
+ p_cpo = empty_string_option;
// Disable error messages, it will make current exception
// invalid
emsg_off++;
@@ -1365,14 +1382,13 @@ void ex_catch(exarg_T *eap)
if (regmatch.regprog == NULL) {
semsg(_(e_invarg2), pat);
} else {
- //
// 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;
+
+ int prev_got_int = got_int;
got_int = false;
- caught = vim_regexec_nl(&regmatch, current_exception->value, (colnr_T)0);
+ caught = vim_regexec_nl(&regmatch, current_exception->value, 0);
got_int |= prev_got_int;
vim_regfree(regmatch.regprog);
}
@@ -1415,7 +1431,6 @@ void ex_catch(exarg_T *eap)
void ex_finally(exarg_T *eap)
{
int idx;
- int skip = false;
int pending = CSTP_NONE;
cstack_T *const cstack = eap->cstack;
@@ -1439,7 +1454,7 @@ void ex_finally(exarg_T *eap)
if (cstack->cs_flags[idx] & CSF_FINALLY) {
// Give up for a multiple ":finally" and ignore it.
- eap->errmsg = _("E607: multiple :finally");
+ eap->errmsg = _(e_multiple_finally);
return;
}
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
@@ -1451,7 +1466,7 @@ void ex_finally(exarg_T *eap)
// ":finally". After every other error (did_emsg or the conditional
// errors detected above) or after an interrupt (got_int) or an
// exception (did_throw), the finally clause must be executed.
- skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+ int skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
if (!skip) {
// When debugging or a breakpoint was encountered, display the
@@ -1497,8 +1512,8 @@ void ex_finally(exarg_T *eap)
} else {
pending |= (did_throw ? CSTP_THROW : 0);
}
- pending |= did_emsg ? CSTP_ERROR : 0;
- pending |= got_int ? CSTP_INTERRUPT : 0;
+ pending |= did_emsg ? CSTP_ERROR : 0;
+ pending |= got_int ? CSTP_INTERRUPT : 0;
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
cstack->cs_pending[cstack->cs_idx] = (char)pending;
@@ -1644,8 +1659,9 @@ void ex_endtry(exarg_T *eap)
if (!skip) {
report_resume_pending(pending,
- (pending == CSTP_RETURN) ? rettv :
- (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ (pending == CSTP_RETURN)
+ ? rettv
+ : (pending & CSTP_THROW) ? (void *)current_exception : NULL);
switch (pending) {
case CSTP_NONE:
break;
@@ -1979,20 +1995,18 @@ void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_lev
/// Handle ":endfunction" when not after a ":function"
void ex_endfunction(exarg_T *eap)
{
- emsg(_("E193: :endfunction not inside a function"));
+ semsg(_(e_str_not_inside_function), ":endfunction");
}
/// @return true if the string "p" looks like a ":while" or ":for" command.
int has_loop_cmd(char *p)
{
- int len;
-
// skip modifiers, white space and ':'
- for (;;) {
+ while (true) {
while (*p == ' ' || *p == '\t' || *p == ':') {
p++;
}
- len = modifier_len(p);
+ int len = modifier_len(p);
if (len == 0) {
break;
}