patch 9.1.0973: too many strlen() calls in fileio.c

Commit: 
https://github.com/vim/vim/commit/14ede1890f820d119ad521a4cfc2ef4beee5b4d3
Author: John Marriott <basil...@internode.on.net>
Date:   Sun Dec 29 16:14:19 2024 +0100

    patch 9.1.0973: too many strlen() calls in fileio.c
    
    Problem:  too many strlen() calls in fileio.c
    Solution: refactor fileio.c and remove calls to STRLEN(),
              check for out-of-memory condition in buf_check_timestamp()
              (John Marriott)
    
    closes: #16306
    
    Signed-off-by: John Marriott <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/fileio.c b/src/fileio.c
index 41e5b5dbf..2f5710405 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -55,17 +55,23 @@ filemess(
 {
     int                msg_scroll_save;
     int                prev_msg_col = msg_col;
+    size_t     len;
 
     if (msg_silent != 0)
        return;
     msg_add_fname(buf, name);      // put file name in IObuff with quotes
 
     // If it's extremely long, truncate it.
-    if (STRLEN(IObuff) > IOSIZE - 100)
-       IObuff[IOSIZE - 100] = NUL;
+    len = STRLEN(IObuff);
+    if (len > IOSIZE - 100)
+    {
+       len = IOSIZE - 100;
+       IObuff[len] = NUL;
+    }
 
     // Avoid an over-long translation to cause trouble.
-    STRNCAT(IObuff, s, 99);
+    if (*s != NUL)
+       STRNCPY(IObuff + len, s, 99);
 
     /*
      * For the first message may have to start a new line.
@@ -224,6 +230,7 @@ readfile(
 #ifdef FEAT_SODIUM
     int                may_need_lseek = FALSE;
 #endif
+    size_t     fnamelen = 0;
 
     curbuf->b_au_did_filetype = FALSE; // reset before triggering any 
autocommands
 
@@ -336,10 +343,10 @@ readfile(
 
     if (fname != NULL && *fname != NUL)
     {
-       size_t namelen = STRLEN(fname);
+       fnamelen = STRLEN(fname);
 
        // If the name is too long we might crash further on, quit here.
-       if (namelen >= MAXPATHL)
+       if (fnamelen >= MAXPATHL)
        {
            filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
            msg_end();
@@ -350,7 +357,7 @@ readfile(
        // If the name ends in a path separator, we can't open it.  Check here,
        // because reading the file may actually work, but then creating the
        // swap file may destroy it!  Reported on MS-DOS and Win 95.
-       if (after_pathsep(fname, fname + namelen))
+       if (after_pathsep(fname, fname + fnamelen))
        {
            filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
            msg_end();
@@ -776,11 +783,13 @@ readfile(
                // Also write a message in the GUI window, if there is one.
                if (gui.in_use && !gui.dying && !gui.starting)
                {
+                   size_t  plen = STRLEN(_("Reading from stdin..."));
+
                    // make a copy, gui_write() may try to change it
-                   p = vim_strsave((char_u *)_("Reading from stdin..."));
+                   p = vim_strnsave((char_u *)_("Reading from stdin..."), 
plen);
                    if (p != NULL)
                    {
-                       gui_write(p, (int)STRLEN(p));
+                       gui_write(p, (int)plen);
                        vim_free(p);
                    }
                }
@@ -838,7 +847,7 @@ readfile(
        c = enc_utf8;
        if (!c && !read_stdin)
        {
-           fc = fname[STRLEN(fname) - 1];
+           fc = fname[fnamelen - 1];
            if (TOLOWER_ASC(fc) == 'x')
            {
                // Read the first line (and a bit more).  Immediately rewind to
@@ -1001,7 +1010,6 @@ retry:
     converted = need_conversion(fenc);
     if (converted)
     {
-
        // "ucs-bom" means we need to check the first bytes of the file
        // for a BOM.
        if (STRCMP(fenc, ENC_UCSBOM) == 0)
@@ -2481,31 +2489,38 @@ failed:
 
        if (!filtering && !(flags & READ_DUMMY))
        {
+           int buflen;
+
            msg_add_fname(curbuf, sfname);   // fname in IObuff with quotes
            c = FALSE;
 
+           buflen = (int)STRLEN(IObuff);
 #ifdef UNIX
            if (S_ISFIFO(perm))                     // fifo
            {
-               STRCAT(IObuff, _("[fifo]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[fifo]"));
                c = TRUE;
            }
            if (S_ISSOCK(perm))                     // or socket
            {
-               STRCAT(IObuff, _("[socket]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[socket]"));
                c = TRUE;
            }
 # ifdef OPEN_CHR_FILES
            if (S_ISCHR(perm))                      // or character special
            {
-               STRCAT(IObuff, _("[character special]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[character special]"));
                c = TRUE;
            }
 # endif
 #endif
            if (curbuf->b_p_ro)
            {
-               STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       "%s", shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
                c = TRUE;
            }
            if (read_no_eol_lnum)
@@ -2515,22 +2530,26 @@ failed:
            }
            if (ff_error == EOL_DOS)
            {
-               STRCAT(IObuff, _("[CR missing]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("CR missing"));
                c = TRUE;
            }
            if (split)
            {
-               STRCAT(IObuff, _("[long lines split]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[long lines split]"));
                c = TRUE;
            }
            if (notconverted)
            {
-               STRCAT(IObuff, _("[NOT converted]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[NOT converted]"));
                c = TRUE;
            }
            else if (converted)
            {
-               STRCAT(IObuff, _("[converted]"));
+               buflen += vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[converted]"));
                c = TRUE;
            }
 #ifdef FEAT_CRYPT
@@ -2542,19 +2561,20 @@ failed:
 #endif
            if (conv_error != 0)
            {
-               sprintf((char *)IObuff + STRLEN(IObuff),
-                      _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
+               vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
                c = TRUE;
            }
            else if (illegal_byte > 0)
            {
-               sprintf((char *)IObuff + STRLEN(IObuff),
-                        _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
+               vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
                c = TRUE;
            }
            else if (error)
            {
-               STRCAT(IObuff, _("[READ ERRORS]"));
+               vim_snprintf((char *)IObuff + buflen, IOSIZE - buflen,
+                       _("[READ ERRORS]"));
                c = TRUE;
            }
            if (msg_add_fileformat(fileformat))
@@ -3162,22 +3182,17 @@ msg_add_lines(
     long    lnum,
     off_T   nchars)
 {
-    char_u  *p;
+    int  len = (int)STRLEN(IObuff);
 
-    p = IObuff + STRLEN(IObuff);
-
-    if (insert_space)
-       *p++ = ' ';
     if (shortmess(SHM_LINES))
-       vim_snprintf((char *)p, IOSIZE - (p - IObuff),
-               "%ldL, %lldB", lnum, (varnumber_T)nchars);
+       vim_snprintf((char *)IObuff + len, IOSIZE - (size_t)len,
+               "%s%ldL, %lldB", insert_space ? " " : "", lnum, 
(varnumber_T)nchars);
     else
     {
-       sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum);
-       p += STRLEN(p);
-       vim_snprintf((char *)p, IOSIZE - (p - IObuff),
-               NGETTEXT("%lld byte", "%lld bytes", nchars),
-               (varnumber_T)nchars);
+       len += vim_snprintf((char *)IObuff + len, IOSIZE - (size_t)len,
+               NGETTEXT("%s%ld line, ", "%s%ld lines, ", lnum), insert_space ? 
" " : "", lnum);
+       vim_snprintf((char *)IObuff + len, IOSIZE - (size_t)len,
+               NGETTEXT("%lld byte", "%lld bytes", nchars), 
(varnumber_T)nchars);
     }
 }
 
@@ -3585,6 +3600,7 @@ buf_modname(
     char_u     *s;
     char_u     *e;
     char_u     *ptr;
+    size_t     ptrlen;
     int                fnamelen, extlen;
 
     extlen = (int)STRLEN(ext);
@@ -3642,10 +3658,14 @@ buf_modname(
     }
 
     // the file name has at most BASENAMELEN characters.
-    if (STRLEN(ptr) > (unsigned)BASENAMELEN)
-       ptr[BASENAMELEN] = '
+    ptrlen = (size_t)(fnamelen - (ptr - retval));
+    if (ptrlen > (unsigned)BASENAMELEN)
+    {
+       ptrlen = BASENAMELEN;
+       ptr[ptrlen] = NUL;
+    }
 
-    s = ptr + STRLEN(ptr);
+    s = ptr + ptrlen;
 
     /*
      * For 8.3 file names we may have to reduce the length.
@@ -3685,7 +3705,7 @@ buf_modname(
         * If the extension doesn't start with '.', and there already is an
         * extension, it may need to be truncated
         */
-       else if ((int)STRLEN(e) + extlen > 4)
+       else if ((int)(ptrlen - (e - retval)) + extlen > 4)
            s = e + 4 - extlen;
     }
 #ifdef MSWIN
@@ -3703,13 +3723,12 @@ buf_modname(
      * ext can start with '.' and cannot exceed 3 more characters.
      */
     STRCPY(s, ext);
-
     /*
      * Prepend the dot.
      */
     if (prepend_dot && !shortname && *(e = gettail(retval)) != '.')
     {
-       STRMOVE(e + 1, e);
+       mch_memmove(e + 1, e, (size_t)(((fnamelen + extlen) - (e - retval)) + 
1));      // +1 for NUL
        *e = '.';
     }
 
@@ -4111,7 +4130,7 @@ move_lines(buf_T *frombuf, buf_T *tobuf)
     curbuf = tobuf;
     for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
     {
-       p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
+       p = vim_strnsave(ml_get_buf(frombuf, lnum, FALSE), 
ml_get_buf_len(frombuf, lnum));
        if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
        {
            vim_free(p);
@@ -4154,8 +4173,6 @@ buf_check_timestamp(
     stat_T     st;
     int                stat_res;
     int                retval = 0;
-    char_u     *path;
-    char       *tbuf;
     char       *mesg = NULL;
     char       *mesg2 = "";
     int                helpmesg = FALSE;
@@ -4164,7 +4181,6 @@ buf_check_timestamp(
        RELOAD_NORMAL,
        RELOAD_DETECT
     }          reload = RELOAD_NONE;
-    char       *reason;
 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
     int                can_reload = FALSE;
 #endif
@@ -4175,9 +4191,6 @@ buf_check_timestamp(
 #endif
     static int busy = FALSE;
     int                n;
-#ifdef FEAT_EVAL
-    char_u     *s;
-#endif
     bufref_T   bufref;
 
     set_bufref(&bufref, buf);
@@ -4242,21 +4255,51 @@ buf_check_timestamp(
            reload = RELOAD_NORMAL;
        else
        {
+           char    *reason;
+#ifdef FEAT_EVAL
+           size_t  reasonlen;
+#endif
+
            if (stat_res < 0)
+           {
                reason = "deleted";
+#ifdef FEAT_EVAL
+               reasonlen = STRLEN_LITERAL("deleted");
+#endif
+           }
            else if (bufIsChanged(buf))
+           {
                reason = "conflict";
+#ifdef FEAT_EVAL
+               reasonlen = STRLEN_LITERAL("conflict");
+#endif
+           }
            /*
             * Check if the file contents really changed to avoid giving a
             * warning when only the timestamp was set (e.g., checked out of
             * CVS).  Always warn when the buffer was changed.
             */
            else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
+           {
                reason = "changed";
+#ifdef FEAT_EVAL
+               reasonlen = STRLEN_LITERAL("changed");
+#endif
+           }
            else if (orig_mode != buf->b_orig_mode)
+           {
                reason = "mode";
+#ifdef FEAT_EVAL
+               reasonlen = STRLEN_LITERAL("mode");
+#endif
+           }
            else
+           {
                reason = "time";
+#ifdef FEAT_EVAL
+               reasonlen = STRLEN_LITERAL("time");
+#endif
+           }
 
            /*
             * Only give the warning if there are no FileChangedShell
@@ -4265,8 +4308,8 @@ buf_check_timestamp(
             */
            busy = TRUE;
 #ifdef FEAT_EVAL
-           set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
-           set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
+           set_vim_var_string(VV_FCS_REASON, (char_u *)reason, reasonlen);
+           set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", 0);
 #endif
            ++allbuf_lock;
            n = apply_autocmds(EVENT_FILECHANGEDSHELL,
@@ -4278,7 +4321,7 @@ buf_check_timestamp(
                if (!bufref_valid(&bufref))
                    emsg(_(e_filechangedshell_autocommand_deleted_buffer));
 #ifdef FEAT_EVAL
-               s = get_vim_var_str(VV_FCS_CHOICE);
+               char_u  *s = get_vim_var_str(VV_FCS_CHOICE);
                if (STRCMP(s, "reload") == 0 && *reason != 'd')
                    reload = RELOAD_NORMAL;
                else if (STRCMP(s, "edit") == 0)
@@ -4343,80 +4386,86 @@ buf_check_timestamp(
 
     if (mesg != NULL)
     {
+       char_u *path;
+
        path = home_replace_save(buf, buf->b_fname);
        if (path != NULL)
        {
+           size_t  tbufsize;
+           char    *tbuf;
+
            if (!helpmesg)
                mesg2 = "";
-           tbuf = alloc(STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2);
-           sprintf(tbuf, mesg, path);
+           tbufsize = STRLEN(mesg) + STRLEN(path) + 2 + STRLEN(mesg2) + 1; // 
+2 for either '
' or "; "
+                                                                           // 
and +1 for NUL
+           tbuf = alloc(tbufsize);
+           if (tbuf != NULL)
+           {
+               int tbuflen;
+
+               tbuflen = vim_snprintf(tbuf, tbufsize, mesg, path);
 #ifdef FEAT_EVAL
-           // Set warningmsg here, before the unimportant and output-specific
-           // mesg2 has been appended.
-           set_vim_var_string(VV_WARNINGMSG, (char_u *)tbuf, -1);
+               // Set warningmsg here, before the unimportant and 
output-specific
+               // mesg2 has been appended.
+               set_vim_var_string(VV_WARNINGMSG, (char_u *)tbuf, tbuflen);
 #endif
 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
-           if (can_reload)
-           {
-               if (*mesg2 != NUL)
-               {
-                   STRCAT(tbuf, "
");
-                   STRCAT(tbuf, mesg2);
-               }
-               switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"),
-                       (char_u *)tbuf,
-                       (char_u *)_("&OK
&Load File
Load File &and Options"),
-                       1, NULL, TRUE))
+               if (can_reload)
                {
-                   case 2:
-                       reload = RELOAD_NORMAL;
-                       break;
-                   case 3:
-                       reload = RELOAD_DETECT;
-                       break;
+                   if (*mesg2 != NUL)
+                       vim_snprintf(tbuf + tbuflen, tbufsize - tbuflen, "
%s", mesg2);
+                   switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"),
+                           (char_u *)tbuf,
+                           (char_u *)_("&OK
&Load File
Load File &and Options"),
+                           1, NULL, TRUE))
+                   {
+                       case 2:
+                           reload = RELOAD_NORMAL;
+                           break;
+                       case 3:
+                           reload = RELOAD_DETECT;
+                           break;
+                   }
                }
-           }
-           else
+               else
 #endif
-           if (State > MODE_NORMAL_BUSY || (State & MODE_CMDLINE)
-                                                            || already_warned)
-           {
-               if (*mesg2 != NUL)
+               if (State > MODE_NORMAL_BUSY || (State & MODE_CMDLINE)
+                                                                || 
already_warned)
                {
-                   STRCAT(tbuf, "; ");
-                   STRCAT(tbuf, mesg2);
+                   if (*mesg2 != NUL)
+                       vim_snprintf(tbuf + tbuflen, tbufsize - tbuflen, "; 
%s", mesg2);
+                   emsg(tbuf);
+                   retval = 2;
                }
-               emsg(tbuf);
-               retval = 2;
-           }
-           else
-           {
-               if (!autocmd_busy)
+               else
                {
-                   msg_start();
-                   msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
-                   if (*mesg2 != NUL)
-                       msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
-                   msg_clr_eos();
-                   (void)msg_end();
-                   if (emsg_silent == 0 && !in_assert_fails)
+                   if (!autocmd_busy)
                    {
-                       out_flush();
-#ifdef FEAT_GUI
-                       if (!focus)
-#endif
-                           // give the user some time to think about it
-                           ui_delay(1004L, TRUE);
-
-                       // don't redraw and erase the message
-                       redraw_cmdline = FALSE;
+                       msg_start();
+                       msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
+                       if (*mesg2 != NUL)
+                           msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
+                       msg_clr_eos();
+                       (void)msg_end();
+                       if (emsg_silent == 0 && !in_assert_fails)
+                       {
+                           out_flush();
+    #ifdef FEAT_GUI
+                           if (!focus)
+    #endif
+                               // give the user some time to think about it
+                               ui_delay(1004L, TRUE);
+
+                           // don't redraw and erase the message
+                           redraw_cmdline = FALSE;
+                       }
                    }
+                   already_warned = TRUE;
                }
-               already_warned = TRUE;
            }
 
-           vim_free(path);
            vim_free(tbuf);
+           vim_free(path);
        }
     }
 
@@ -4696,19 +4745,19 @@ getftypewfd(WIN32_FIND_DATAW *wfd)
     {
        if (tag == IO_REPARSE_TAG_MOUNT_POINT)
            return (char_u*)"junction";
-       else if (tag == IO_REPARSE_TAG_SYMLINK)
+       if (tag == IO_REPARSE_TAG_SYMLINK)
        {
            if (flag & FILE_ATTRIBUTE_DIRECTORY)
                return (char_u*)"linkd";
-           else
-               return (char_u*)"link";
+
+           return (char_u*)"link";
        }
        return (char_u*)"reparse";      // unknown reparse point type
     }
     if (flag & FILE_ATTRIBUTE_DIRECTORY)
        return (char_u*)"dir";
-    else
-       return (char_u*)"file";
+
+    return (char_u*)"file";
 }
 
     static dict_T *
@@ -4793,7 +4842,6 @@ create_readdirex_item(char_u *path, char_u *name)
        ret = mch_stat(p, &st);
        if (ret < 0)
            q = (char_u*)"link";
-
     }
     vim_free(p);
 
@@ -4876,10 +4924,10 @@ compare_readdirex_item(const void *p1, const void *p2)
     name2 = dict_get_string(*(dict_T**)p2, "name", FALSE);
     if (readdirex_sort == READDIR_SORT_BYTE)
        return STRCMP(name1, name2);
-    else if (readdirex_sort == READDIR_SORT_IC)
+    if (readdirex_sort == READDIR_SORT_IC)
        return STRICMP(name1, name2);
-    else
-       return STRCOLL(name1, name2);
+
+    return STRCOLL(name1, name2);
 }
 
     static int
@@ -4887,10 +4935,10 @@ compare_readdir_item(const void *s1, const void *s2)
 {
     if (readdirex_sort == READDIR_SORT_BYTE)
        return STRCMP(*(char **)s1, *(char **)s2);
-    else if (readdirex_sort == READDIR_SORT_IC)
+    if (readdirex_sort == READDIR_SORT_IC)
        return STRICMP(*(char **)s1, *(char **)s2);
-    else
-       return STRCOLL(*(char **)s1, *(char **)s2);
+
+    return STRCOLL(*(char **)s1, *(char **)s2);
 }
 #endif
 
@@ -4919,6 +4967,7 @@ readdir_core(
     HANDLE             hFind = INVALID_HANDLE_VALUE;
     WIN32_FIND_DATAW    wfd;
     WCHAR              *wn = NULL;     // UTF-16 name, NULL when not used.
+    char_u             *p_end;
 # else
     DIR                        *dirp;
     struct dirent      *dp;
@@ -4944,11 +4993,11 @@ readdir_core(
     if (buf == NULL)
        return FAIL;
     STRNCPY(buf, path, MAXPATHL-5);
-    p = buf + STRLEN(buf);
+    p = p_end = buf + STRLEN(buf);
     MB_PTR_BACK(buf, p);
     if (*p == '\' || *p == '/')
-       *p = NUL;
-    STRCAT(p, "\*");
+       p_end = p;
+    STRCPY(p_end, "\*");
 
     wn = enc_to_utf16(buf, NULL);
     if (wn != NULL)
@@ -5118,9 +5167,6 @@ readdir_core(
 delete_recursive(char_u *name)
 {
     int result = 0;
-    int                i;
-    char_u     *exp;
-    garray_T   ga;
 
     // A symbolic link to a directory itself is deleted, not the directory it
     // points to.
@@ -5132,15 +5178,19 @@ delete_recursive(char_u *name)
 # endif
            )
     {
-       exp = vim_strsave(name);
+       char_u      *exp = vim_strsave(name);
+       garray_T    ga;
+
        if (exp == NULL)
            return -1;
        if (readdir_core(&ga, exp, FALSE, NULL, NULL, READDIR_SORT_NONE) == OK)
        {
+           int len = vim_snprintf((char *)NameBuff, MAXPATHL, "%s/", exp);
+           int i;
+
            for (i = 0; i < ga.ga_len; ++i)
            {
-               vim_snprintf((char *)NameBuff, MAXPATHL, "%s/%s", exp,
-                                           ((char_u **)ga.ga_data)[i]);
+               vim_snprintf((char *)NameBuff + len, MAXPATHL - len, "%s", 
((char_u **)ga.ga_data)[i]);
                if (delete_recursive(NameBuff) != 0)
                    // Remember the failure but continue deleting any further
                    // entries.
@@ -5226,6 +5276,7 @@ vim_deltempdir(void)
 vim_settempdir(char_u *tempdir)
 {
     char_u     *buf;
+    size_t     buflen;
 
     buf = alloc(MAXPATHL + 2);
     if (buf == NULL)
@@ -5233,8 +5284,13 @@ vim_settempdir(char_u *tempdir)
 
     if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
        STRCPY(buf, tempdir);
-    add_pathsep(buf);
-    vim_tempdir = vim_strsave(buf);
+    buflen = STRLEN(buf);
+    if (!after_pathsep(buf, buf + buflen))
+    {
+       STRCPY(buf + buflen, PATHSEPSTR);
+       buflen += STRLEN_LITERAL(PATHSEPSTR);
+    }
+    vim_tempdir = vim_strnsave(buf, buflen);
 # if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD)
     vim_opentempdir();
 # endif
@@ -5286,7 +5342,6 @@ vim_tempname(
        for (i = 0; i < (int)ARRAY_LENGTH(tempdirs); ++i)
        {
 # ifndef HAVE_MKDTEMP
-           size_t      itmplen;
            long        nr;
            long        off;
 # endif
@@ -5296,8 +5351,14 @@ vim_tempname(
            expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
            if (itmp[0] != '$' && mch_isdir(itmp))
            {
+               size_t  itmplen = STRLEN(itmp);
+
                // directory exists
-               add_pathsep(itmp);
+               if (!after_pathsep(itmp, itmp + itmplen))
+               {
+                   STRCPY(itmp + itmplen, PATHSEPSTR);
+                   itmplen += STRLEN_LITERAL(PATHSEPSTR);
+               }
 
 # ifdef HAVE_MKDTEMP
                {
@@ -5307,7 +5368,8 @@ vim_tempname(
                    mode_t      umask_save = umask(077);
 #  endif
                    // Leave room for filename
-                   STRCAT(itmp, "vXXXXXX");
+                   STRCPY(itmp + itmplen, "vXXXXXX");
+                   itmplen += STRLEN_LITERAL("vXXXXXX");
                    if (mkdtemp((char *)itmp) != NULL)
                        vim_settempdir(itmp);
 #  if defined(UNIX) || defined(VMS)
@@ -5320,7 +5382,6 @@ vim_tempname(
                // otherwise it doesn't matter.  The use of mkdir() avoids any
                // security problems because of the predictable number.
                nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
-               itmplen = STRLEN(itmp);
 
                // Try up to 10000 different values until we find a name that
                // doesn't exist.
@@ -5331,7 +5392,7 @@ vim_tempname(
                    mode_t      umask_save;
 #  endif
 
-                   sprintf((char *)itmp + itmplen, "v%ld", nr + off);
+                   vim_snprintf((char *)itmp + itmplen, sizeof(itmp) - 
itmplen, "v%ld", nr + off);
 #  ifndef EEXIST
                    // If mkdir() does not set errno to EEXIST, check for
                    // existing file here.  There is a race condition then,
@@ -5372,20 +5433,20 @@ vim_tempname(
     {
        // There is no need to check if the file exists, because we own the
        // directory and nobody else creates a file in it.
-       sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
-       return vim_strsave(itmp);
+       int itmplen = vim_snprintf((char *)itmp, sizeof(itmp), "%s%ld", 
vim_tempdir, temp_count++);
+       return vim_strnsave(itmp, (size_t)itmplen);
     }
 
     return NULL;
 
 #else // TEMPDIRNAMES
+    char_u     *p;
 
 # ifdef MSWIN
     WCHAR      wszTempFile[_MAX_PATH + 1];
     WCHAR      buf4[4];
     WCHAR      *chartab = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     char_u     *retval;
-    char_u     *p;
     char_u     *shname;
     long       i;
 
@@ -5405,7 +5466,7 @@ vim_tempname(
     if (GetTempFileNameW(wszTempFile, buf4, 0, itmp) == 0)
        return NULL;
     if (!keep)
-       // GetTempFileName() will create the file, we don't want that
+       // GetTempFileNameW() will create the file, we don't want that
        (void)DeleteFileW(itmp);
 
     // Backslashes in a temp file name cause problems when filtering with
@@ -5422,34 +5483,32 @@ vim_tempname(
     return retval;
 
 # else // MSWIN
+    int                itmplen;
 
 #  ifdef USE_TMPNAM
-    char_u     *p;
-
     // tmpnam() will make its own name
     p = tmpnam((char *)itmp);
     if (p == NULL || *p == NUL)
        return NULL;
 #  else
-    char_u     *p;
 
 #   ifdef VMS_TEMPNAM
     // mktemp() is not working on VMS.  It seems to be
     // a do-nothing function. Therefore we use tempnam().
-    sprintf((char *)itmp, "VIM%c", extra_char);
+    vim_snprintf((char *)itmp, sizeof(itmp), "VIM%c", extra_char);
     p = (char_u *)tempnam("tmp:", (char *)itmp);
     if (p != NULL)
     {
        // VMS will use '.LIS' if we don't explicitly specify an extension,
        // and VIM will then be unable to find the file later
-       STRCPY(itmp, p);
-       STRCAT(itmp, ".txt");
+       itmplen = vim_snprintf((char *)itmp, sizeof(itmp), "%s.txt", p);
        free(p);
     }
     else
        return NULL;
 #   else
     STRCPY(itmp, TEMPNAME);
+    itmplen = STRLEN_LITERAL(TEMPNAME);
     if ((p = vim_strchr(itmp, '?')) != NULL)
        *p = extra_char;
     if (mktemp((char *)itmp) == NULL)
@@ -5457,7 +5516,7 @@ vim_tempname(
 #   endif
 #  endif
 
-    return vim_strsave(itmp);
+    return vim_strnsave(itmp, (size_t)itmplen);
 # endif // MSWIN
 #endif // TEMPDIRNAMES
 }
diff --git a/src/version.c b/src/version.c
index 18a736c6e..f37ad9418 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    973,
 /**/
     972,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1tRvEx-00BnlK-8U%40256bit.org.

Raspunde prin e-mail lui