aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikolai Aleksandrovich Pavlov <kp-pav@yandex.ru>2017-02-11 21:47:02 +0300
committerJustin M. Keyes <justinkz@gmail.com>2017-02-11 19:47:02 +0100
commitabdbfd26bc7f91cb6fda8feb758ffd020fb58754 (patch)
tree866d2cc4db059f7392d30715483ca8c0eb52be6b /src
parentb1cf50c6846790fc1846a36ced3ba19134afef64 (diff)
downloadrneovim-abdbfd26bc7f91cb6fda8feb758ffd020fb58754.tar.gz
rneovim-abdbfd26bc7f91cb6fda8feb758ffd020fb58754.tar.bz2
rneovim-abdbfd26bc7f91cb6fda8feb758ffd020fb58754.zip
eval: Add id() function and make printf("%p") return something useful (#6095)
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c28
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval_defs.h2
-rw-r--r--src/nvim/message.c37
4 files changed, 57 insertions, 11 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 823b621638..bbb6565509 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -498,6 +498,14 @@ static PMap(uint64_t) *jobs = NULL;
static uint64_t last_timer_id = 0;
static PMap(uint64_t) *timers = NULL;
+/// Dummy va_list for passing to vim_snprintf
+///
+/// Used because:
+/// - passing a NULL pointer doesn't work when va_list isn't a pointer
+/// - locally in the function results in a "used before set" warning
+/// - using va_start() to initialize it gives "function with fixed args" error
+static va_list dummy_ap;
+
static const char *const msgpack_type_names[] = {
[kMPNil] = "nil",
[kMPBoolean] = "boolean",
@@ -12122,6 +12130,16 @@ static void dict_list(typval_T *argvars, typval_T *rettv, int what)
}
}
+/// "id()" function
+static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const int len = vim_vsnprintf(NULL, 0, "%p", dummy_ap, argvars);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = xmalloc(len + 1);
+ vim_vsnprintf((char *)rettv->vval.v_string, len + 1, "%p", dummy_ap, argvars);
+}
+
/*
* "items(dict)" function
*/
@@ -13628,12 +13646,6 @@ static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = lnum;
}
-/* This dummy va_list is here because:
- * - passing a NULL pointer doesn't work when va_list isn't a pointer
- * - locally in the function results in a "used before set" warning
- * - using va_start() to initialize it gives "function with fixed args" error */
-static va_list ap;
-
/*
* "printf()" function
*/
@@ -13650,11 +13662,11 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/* Get the required length, allocate the buffer and do it for real. */
did_emsg = FALSE;
fmt = (char *)get_tv_string_buf(&argvars[0], buf);
- len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
+ len = vim_vsnprintf(NULL, 0, fmt, dummy_ap, argvars + 1);
if (!did_emsg) {
char *s = xmalloc(len + 1);
rettv->vval.v_string = (char_u *)s;
- (void)vim_vsnprintf(s, len + 1, fmt, ap, argvars + 1);
+ (void)vim_vsnprintf(s, len + 1, fmt, dummy_ap, argvars + 1);
}
did_emsg |= saved_did_emsg;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index e0b72feb19..964b061e95 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -168,6 +168,7 @@ return {
invert={args=1},
isdirectory={args=1},
islocked={args=1},
+ id={args=1},
items={args=1},
jobclose={args={1, 2}},
jobpid={args=1},
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index f478d19ca1..616c89671b 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -49,7 +49,7 @@ typedef enum {
typedef struct {
VarType v_type; ///< Variable type.
VarLockStatus v_lock; ///< Variable lock status.
- union {
+ union typval_vval_union {
varnumber_T v_number; ///< Number, for VAR_NUMBER.
SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
float_T v_float; ///< Floating-point number, for VAR_FLOAT.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 6104adf2c7..ad1c63eeac 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -11,6 +11,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/assert.h"
#include "nvim/message.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
@@ -3043,6 +3044,38 @@ static char *tv_str(typval_T *tvs, int *idxp)
return s;
}
+/// Get pointer argument from the next entry in tvs
+///
+/// First entry is 1. Returns NULL for an error.
+///
+/// @param[in] tvs List of typval_T values.
+/// @param[in,out] idxp Pointer to the index of the current value.
+///
+/// @return Pointer stored in typval_T or NULL.
+static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+#define OFF(attr) offsetof(union typval_vval_union, attr)
+ STATIC_ASSERT(
+ OFF(v_string) == OFF(v_list)
+ && OFF(v_string) == OFF(v_dict)
+ && OFF(v_string) == OFF(v_partial)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
+ "Strings, dictionaries, lists and partials are expected to be pointers, "
+ "so that all three of them can be accessed via v_string");
+#undef OFF
+ const int idx = *idxp - 1;
+ if (tvs[idx].v_type == VAR_UNKNOWN) {
+ EMSG(_(e_printf));
+ return NULL;
+ } else {
+ (*idxp)++;
+ return tvs[idx].vval.v_string;
+ }
+}
+
/*
* Get float argument from "idxp" entry in "tvs". First entry is 1.
*/
@@ -3369,11 +3402,11 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
size_t size_t_arg = 0;
// only defined for p conversion
- void *ptr_arg = NULL;
+ const void *ptr_arg = NULL;
if (fmt_spec == 'p') {
length_modifier = '\0';
- ptr_arg = tvs ? (void *)tv_str(tvs, &arg_idx) : va_arg(ap, void *);
+ ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *);
if (ptr_arg) {
arg_sign = 1;
}