diff options
Diffstat (limited to 'src/nvim/memory.c')
-rw-r--r-- | src/nvim/memory.c | 119 |
1 files changed, 88 insertions, 31 deletions
diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 92ead873ae..328b96fd5c 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -1,3 +1,6 @@ +// 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 + // Various routines dealing with allocation and deallocation of memory. #include <assert.h> @@ -342,10 +345,6 @@ char *xstpcpy(char *restrict dst, const char *restrict src) /// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than /// maxlen, zeroes will be written to the remaining bytes. /// -/// TODO(aktau): I don't see a good reason to have this last behaviour, and -/// it is potentially wasteful. Could we perhaps deviate from the standard -/// and not zero the rest of the buffer? -/// /// @param dst /// @param src /// @param maxlen @@ -364,29 +363,58 @@ char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen) } } -/// xstrlcpy - Copy a %NUL terminated string into a sized buffer +/// xstrlcpy - Copy a NUL-terminated string into a sized buffer /// -/// Compatible with *BSD strlcpy: the result is always a valid -/// NUL-terminated string that fits in the buffer (unless, -/// of course, the buffer size is zero). It does not pad -/// out the result like strncpy() does. +/// Compatible with *BSD strlcpy: the result is always a valid NUL-terminated +/// string that fits in the buffer (unless, of course, the buffer size is +/// zero). It does not pad out the result like strncpy() does. /// -/// @param dst Where to copy the string to -/// @param src Where to copy the string from -/// @param size Size of destination buffer -/// @return Length of the source string (i.e.: strlen(src)) -size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t size) +/// @param dst Buffer to store the result +/// @param src String to be copied +/// @param dsize Size of `dst` +/// @return strlen(src). If retval >= dstsize, truncation occurs. +size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize) FUNC_ATTR_NONNULL_ALL { - size_t ret = strlen(src); + size_t slen = strlen(src); - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; + if (dsize) { + size_t len = MIN(slen, dsize - 1); memcpy(dst, src, len); dst[len] = '\0'; } - return ret; + return slen; // Does not include NUL. +} + +/// Appends `src` to string `dst` of size `dsize` (unlike strncat, dsize is the +/// full size of `dst`, not space left). At most dsize-1 characters +/// will be copied. Always NUL terminates. `src` and `dst` may overlap. +/// +/// @see vim_strcat from Vim. +/// @see strlcat from OpenBSD. +/// +/// @param dst Buffer to be appended-to. Must have a NUL byte. +/// @param src String to put at the end of `dst` +/// @param dsize Size of `dst` including NUL byte. Must be greater than 0. +/// @return strlen(src) + strlen(initial dst) +/// If retval >= dsize, truncation occurs. +size_t xstrlcat(char *const dst, const char *const src, const size_t dsize) + FUNC_ATTR_NONNULL_ALL +{ + assert(dsize > 0); + const size_t dlen = strlen(dst); + assert(dlen < dsize); + const size_t slen = strlen(src); + + if (slen > dsize - dlen - 1) { + memmove(dst + dlen, src, dsize - dlen - 1); + dst[dsize - 1] = '\0'; + } else { + memmove(dst + dlen, src, slen + 1); + } + + return slen + dlen; // Does not include NUL. } /// strdup() wrapper @@ -401,6 +429,19 @@ char *xstrdup(const char *str) return xmemdupz(str, strlen(str)); } +/// strdup() wrapper +/// +/// Unlike xstrdup() allocates a new empty string if it receives NULL. +char *xstrdupnul(const char *const str) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET +{ + if (str == NULL) { + return xmallocz(0); + } else { + return xstrdup(str); + } +} + /// A version of memchr that starts the search at `src + len`. /// /// Based on glibc's memrchr. @@ -446,6 +487,20 @@ void *xmemdup(const void *data, size_t len) return memcpy(xmalloc(len), data, len); } +/// Returns true if strings `a` and `b` are equal. Arguments may be NULL. +bool strequal(const char *a, const char *b) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return (a == NULL && b == NULL) || (a && b && strcmp(a, b) == 0); +} + +/// Case-insensitive `strequal`. +bool striequal(const char *a, const char *b) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return (a == NULL && b == NULL) || (a && b && STRICMP(a, b) == 0); +} + /* * Avoid repeating the error message many times (they take 1 second each). * Did_outofmem_msg is reset when a character is read. @@ -530,7 +585,7 @@ void free_all_mem(void) p_ea = false; if (first_tabpage->tp_next != NULL) do_cmdline_cmd("tabonly!"); - if (firstwin != lastwin) + if (!ONE_WINDOW) do_cmdline_cmd("only!"); /* Free all spell info. */ @@ -596,18 +651,6 @@ void free_all_mem(void) /* Destroy all windows. Must come before freeing buffers. */ win_free_all(); - /* Free all buffers. Reset 'autochdir' to avoid accessing things that - * were freed already. */ - p_acd = false; - for (buf = firstbuf; buf != NULL; ) { - nextbuf = buf->b_next; - close_buffer(NULL, buf, DOBUF_WIPE, false); - if (buf_valid(buf)) - buf = nextbuf; /* didn't work, try next one */ - else - buf = firstbuf; - } - free_cmdline_buf(); /* Clear registers. */ @@ -631,6 +674,20 @@ void free_all_mem(void) eval_clear(); + // Free all buffers. Reset 'autochdir' to avoid accessing things that + // were freed already. + // Must be after eval_clear to avoid it trying to access b:changedtick after + // freeing it. + p_acd = false; + for (buf = firstbuf; buf != NULL; ) { + bufref_T bufref; + set_bufref(&bufref, buf); + nextbuf = buf->b_next; + close_buffer(NULL, buf, DOBUF_WIPE, false); + // Didn't work, try next one. + buf = bufref_valid(&bufref) ? nextbuf : firstbuf; + } + /* screenlines (can't display anything now!) */ free_screenlines(); |