From 1a89819dcbe51883cb63c411179af1db77ffb32d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 22 Dec 2014 22:13:02 -0800 Subject: [PATCH] Prefer stpcpy to strcat * admin/merge-gnulib (GNULIB_MODULES): Add stpcpy. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * lib/stpcpy.c, m4/stpcpy.m4: New files, from gnulib. * src/callproc.c (child_setup): * src/dbusbind.c (xd_signature_cat): * src/doc.c (get_doc_string, Fsnarf_documentation): * src/editfns.c (Fuser_full_name): * src/frame.c (xrdb_get_resource): * src/gtkutil.c (xg_get_file_with_chooser): * src/tparam.c (tparam1): * src/xfns.c (xic_create_fontsetname): * src/xrdb.c (gethomedir, get_user_db, get_environ_db): * src/xsmfns.c (smc_save_yourself_CB): Rewrite to avoid the need for strcat, typically by using stpcpy. strcat tends to be part of O(N**2) algorithms. --- ChangeLog | 17 +++++++++++++++++ admin/merge-gnulib | 2 +- lib/gnulib.mk | 11 ++++++++++- lib/stpcpy.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ m4/gnulib-comp.m4 | 9 +++++++++ m4/stpcpy.m4 | 25 +++++++++++++++++++++++++ src/callproc.c | 7 ++----- src/dbusbind.c | 2 +- src/doc.c | 6 ++---- src/editfns.c | 5 ++--- src/frame.c | 20 ++++++++++---------- src/gtkutil.c | 6 +++--- src/tparam.c | 4 ++-- src/xfns.c | 34 +++++++++++++++++----------------- src/xrdb.c | 45 +++++++++++++++++++++------------------------ src/xsmfns.c | 6 ++---- 16 files changed, 173 insertions(+), 75 deletions(-) create mode 100644 lib/stpcpy.c create mode 100644 m4/stpcpy.m4 diff --git a/ChangeLog b/ChangeLog index 7e68314..acafad6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2014-12-23 Paul Eggert + Prefer stpcpy to strcat + * admin/merge-gnulib (GNULIB_MODULES): Add stpcpy. + * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. + * lib/stpcpy.c, m4/stpcpy.m4: New files, from gnulib. + * src/callproc.c (child_setup): + * src/dbusbind.c (xd_signature_cat): + * src/doc.c (get_doc_string, Fsnarf_documentation): + * src/editfns.c (Fuser_full_name): + * src/frame.c (xrdb_get_resource): + * src/gtkutil.c (xg_get_file_with_chooser): + * src/tparam.c (tparam1): + * src/xfns.c (xic_create_fontsetname): + * src/xrdb.c (gethomedir, get_user_db, get_environ_db): + * src/xsmfns.c (smc_save_yourself_CB): + Rewrite to avoid the need for strcat, typically by using stpcpy. + strcat tends to be part of O(N**2) algorithms. + Merge from gnulib 2014-12-20 utimens: remove unnecessary assert 2014-12-16 stdalign: port better to HP compilers diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 64514f7..84c6ebf 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -36,7 +36,7 @@ GNULIB_MODULES=' manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio - strftime strtoimax strtoumax symlink sys_stat + stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings diff --git a/lib/gnulib.mk b/lib/gnulib.mk index 740ebb1..27a5964 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk @@ -21,7 +21,7 @@ # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. -# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings +# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings MOSTLYCLEANFILES += core *.stackdump @@ -1214,6 +1214,15 @@ EXTRA_DIST += stdlib.in.h ## end gnulib module stdlib +## begin gnulib module stpcpy + + +EXTRA_DIST += stpcpy.c + +EXTRA_libgnu_a_SOURCES += stpcpy.c + +## end gnulib module stpcpy + ## begin gnulib module strftime libgnu_a_SOURCES += strftime.c diff --git a/lib/stpcpy.c b/lib/stpcpy.c new file mode 100644 index 0000000..880a706 --- /dev/null +++ b/lib/stpcpy.c @@ -0,0 +1,49 @@ +/* stpcpy.c -- copy a string and return pointer to end of new string + Copyright (C) 1992, 1995, 1997-1998, 2006, 2009-2014 Free Software + Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to address@hidden + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include + +#undef __stpcpy +#ifdef _LIBC +# undef stpcpy +#endif + +#ifndef weak_alias +# define __stpcpy stpcpy +#endif + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +__stpcpy (char *dest, const char *src) +{ + register char *d = dest; + register const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} +#ifdef weak_alias +weak_alias (__stpcpy, stpcpy) +#endif diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 39ec8ae..49fdf5e 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -123,6 +123,7 @@ AC_DEFUN([gl_EARLY], # Code from module stdint: # Code from module stdio: # Code from module stdlib: + # Code from module stpcpy: # Code from module strftime: # Code from module string: # Code from module strtoimax: @@ -341,6 +342,12 @@ AC_DEFUN([gl_INIT], gl_STDINT_H gl_STDIO_H gl_STDLIB_H + gl_FUNC_STPCPY + if test $HAVE_STPCPY = 0; then + AC_LIBOBJ([stpcpy]) + gl_PREREQ_STPCPY + fi + gl_STRING_MODULE_INDICATOR([stpcpy]) gl_FUNC_GNU_STRFTIME gl_HEADER_STRING_H gl_FUNC_STRTOIMAX @@ -889,6 +896,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/stdint.in.h lib/stdio.in.h lib/stdlib.in.h + lib/stpcpy.c lib/strftime.c lib/strftime.h lib/string.in.h @@ -995,6 +1003,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/stdint.m4 m4/stdio_h.m4 m4/stdlib_h.m4 + m4/stpcpy.m4 m4/strftime.m4 m4/string_h.m4 m4/strtoimax.m4 diff --git a/m4/stpcpy.m4 b/m4/stpcpy.m4 new file mode 100644 index 0000000..966ba95 --- /dev/null +++ b/m4/stpcpy.m4 @@ -0,0 +1,25 @@ +# stpcpy.m4 serial 8 +dnl Copyright (C) 2002, 2007, 2009-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_STPCPY], +[ + dnl Persuade glibc to declare stpcpy(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + dnl The stpcpy() declaration in lib/string.in.h uses 'restrict'. + AC_REQUIRE([AC_C_RESTRICT]) + + AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) + AC_CHECK_FUNCS([stpcpy]) + if test $ac_cv_func_stpcpy = no; then + HAVE_STPCPY=0 + fi +]) + +# Prerequisites of lib/stpcpy.c. +AC_DEFUN([gl_PREREQ_STPCPY], [ + : +]) diff --git a/src/callproc.c b/src/callproc.c index a677334..7705ab0 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -1315,13 +1315,10 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, if (STRINGP (display)) { - char *vdata; - if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display)) exec_failed (new_argv[0], ENOMEM); - vdata = alloca (sizeof "DISPLAY=" + SBYTES (display)); - strcpy (vdata, "DISPLAY="); - strcat (vdata, SSDATA (display)); + char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display)); + strcpy (stpcpy (vdata, "DISPLAY="), SSDATA (display)); new_env = add_env (env, new_env, vdata); } diff --git a/src/dbusbind.c b/src/dbusbind.c index 4852739..983b05c 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c @@ -357,7 +357,7 @@ xd_signature_cat (char *signature, char const *x) ptrdiff_t xlen = strlen (x); if (DBUS_MAXIMUM_SIGNATURE_LENGTH - xlen <= siglen) string_overflow (); - strcat (signature, x); + strcpy (signature + siglen, x); } /* Compute SIGNATURE of OBJECT. It must have a form that it can be diff --git a/src/doc.c b/src/doc.c index 1b87c23..c6c3251 100644 --- a/src/doc.c +++ b/src/doc.c @@ -137,8 +137,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) { /* Preparing to dump; DOC file is probably not installed. So check in ../etc. */ - strcpy (name, "../etc/"); - strcat (name, SSDATA (file)); + strcpy (stpcpy (name, "../etc/"), SSDATA (file)); fd = emacs_open (name, O_RDONLY, 0); } @@ -594,8 +593,7 @@ the same file name is found in the `doc-directory'. */) count = SPECPDL_INDEX (); USE_SAFE_ALLOCA; name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1); - strcpy (name, dirname); - strcat (name, SSDATA (filename)); /*** Add this line ***/ + strcpy (stpcpy (name, dirname), SSDATA (filename)); /*** Add this line ***/ /* Vbuild_files is nil when temacs is run, and non-nil after that. */ if (NILP (Vbuild_files)) diff --git a/src/editfns.c b/src/editfns.c index 0a07886..955e962 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -1350,10 +1350,9 @@ name, or nil if there is no such user. */) USE_SAFE_ALLOCA; char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1); memcpy (r, p, q - p); - r[q - p] = 0; - strcat (r, SSDATA (login)); + char *s = stpcpy (&r[q - p], SSDATA (login)); r[q - p] = upcase ((unsigned char) r[q - p]); - strcat (r, q + 1); + strcpy (s, q + 1); full = build_string (r); SAFE_FREE (); } diff --git a/src/frame.c b/src/frame.c index 3127366..d71a26c 100644 --- a/src/frame.c +++ b/src/frame.c @@ -4076,23 +4076,23 @@ xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Li /* Start with emacs.FRAMENAME for the name (the specific one) and with `Emacs' for the class key (the general one). */ - lispstpcpy (name_key, Vx_resource_name); - lispstpcpy (class_key, Vx_resource_class); + char *nz = lispstpcpy (name_key, Vx_resource_name); + char *cz = lispstpcpy (class_key, Vx_resource_class); - strcat (class_key, "."); - strcat (class_key, SSDATA (class)); + *cz++ = '.'; + cz = stpcpy (cz, SSDATA (class)); if (!NILP (component)) { - strcat (class_key, "."); - strcat (class_key, SSDATA (subclass)); + *cz++ = '.'; + strcpy (cz, SSDATA (subclass)); - strcat (name_key, "."); - strcat (name_key, SSDATA (component)); + *nz++ = '.'; + nz = stpcpy (nz, SSDATA (component)); } - strcat (name_key, "."); - strcat (name_key, SSDATA (attribute)); + *nz++ = '.'; + strcpy (nz, SSDATA (attribute)); char *value = x_get_string_resource (rdb, name_key, class_key); SAFE_FREE(); diff --git a/src/gtkutil.c b/src/gtkutil.c index 9465d54..f61cbc2 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1839,12 +1839,12 @@ xg_get_file_with_chooser (struct frame *f, if (x_gtk_file_dialog_help_text) { - msgbuf[0] = '\0'; + char *z = msgbuf; /* Gtk+ 2.10 has the file name text entry box integrated in the dialog. Show the C-l help text only for versions < 2.10. */ if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE) - strcat (msgbuf, "\nType C-l to display a file name text entry box.\n"); - strcat (msgbuf, "\nIf you don't like this file selector, use the " + z = stpcpy (z, "\nType C-l to display a file name text entry box.\n"); + strcpy (z, "\nIf you don't like this file selector, use the " "corresponding\nkey binding or customize " "use-file-dialog to turn it off."); diff --git a/src/tparam.c b/src/tparam.c index e02cea3..b0cd004 100644 --- a/src/tparam.c +++ b/src/tparam.c @@ -255,9 +255,9 @@ tparam1 (const char *string, char *outstring, int len, } *op = 0; while (doup-- > 0) - strcat (op, up); + op = stpcpy (op, up); while (doleft-- > 0) - strcat (op, left); + op = stpcpy (op, left); return outstring; } diff --git a/src/xfns.c b/src/xfns.c index 1b17311..ba2601d 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1710,13 +1710,14 @@ xic_create_fontsetname (const char *base_fontname, int motif) { const char *sep = motif ? ";" : ","; char *fontsetname; + char *z; /* Make a fontset name from the base font name. */ if (xic_default_fontset == base_fontname) { /* There is no base font name, use the default. */ fontsetname = xmalloc (strlen (base_fontname) + 2); - strcpy (fontsetname, base_fontname); + z = stpcpy (fontsetname, base_fontname); } else { @@ -1737,9 +1738,9 @@ xic_create_fontsetname (const char *base_fontname, int motif) Use the specified font plus the default. */ fontsetname = xmalloc (strlen (base_fontname) + strlen (xic_default_fontset) + 3); - strcpy (fontsetname, base_fontname); - strcat (fontsetname, sep); - strcat (fontsetname, xic_default_fontset); + z = stpcpy (fontsetname, base_fontname); + z = stpcpy (z, sep); + z = stpcpy (z, xic_default_fontset); } else { @@ -1800,27 +1801,26 @@ xic_create_fontsetname (const char *base_fontname, int motif) /* Build the font spec that matches all. */ len = p - p2 + strlen (allcs) + strlen (all) + strlen (allfamilies) + 1; font_all = alloca (len); - strcpy (font_all, allfamilies); - strcat (font_all, all); - memcpy (font_all + strlen (all) + strlen (allfamilies), p2, p - p2); - strcpy (font_all + strlen (all) + strlen (allfamilies) + (p - p2), - allcs); + z = stpcpy (font_all, allfamilies); + z = stpcpy (z, all); + memcpy (z, p2, p - p2); + strcpy (z + (p - p2), allcs); /* Build the actual font set name. */ len = strlen (base_fontname) + strlen (font_allcs) + strlen (font_allfamilies) + strlen (font_all) + 5; fontsetname = xmalloc (len); - strcpy (fontsetname, base_fontname); - strcat (fontsetname, sep); - strcat (fontsetname, font_allcs); - strcat (fontsetname, sep); - strcat (fontsetname, font_allfamilies); - strcat (fontsetname, sep); - strcat (fontsetname, font_all); + z = stpcpy (fontsetname, base_fontname); + z = stpcpy (z, sep); + z = stpcpy (z, font_allcs); + z = stpcpy (z, sep); + z = stpcpy (z, font_allfamilies); + z = stpcpy (z, sep); + z = stpcpy (z, font_all); } } if (motif) - return strcat (fontsetname, ":"); + strcpy (z, ":"); return fontsetname; } #endif /* HAVE_X_WINDOWS && USE_X_TOOLKIT */ diff --git a/src/xrdb.c b/src/xrdb.c index 32ad3c7..c653373 100644 --- a/src/xrdb.c +++ b/src/xrdb.c @@ -232,9 +232,10 @@ gethomedir (void) if (ptr == NULL) return xstrdup ("/"); - copy = xmalloc (strlen (ptr) + 2); - strcpy (copy, ptr); - return strcat (copy, "/"); + ptrdiff_t len = strlen (ptr); + copy = xmalloc (len + 2); + strcpy (copy + len, "/"); + return memcpy (copy, ptr, len); } @@ -334,6 +335,7 @@ get_user_app (const char *class) return db; } +static char const xdefaults[] = ".Xdefaults"; static XrmDatabase get_user_db (Display *display) @@ -351,16 +353,12 @@ get_user_db (Display *display) db = XrmGetStringDatabase (xdefs); else { - char *home; - char *xdefault; - - home = gethomedir (); - xdefault = xmalloc (strlen (home) + sizeof ".Xdefaults"); - strcpy (xdefault, home); - strcat (xdefault, ".Xdefaults"); - db = XrmGetFileDatabase (xdefault); - xfree (home); - xfree (xdefault); + char *home = gethomedir (); + ptrdiff_t homelen = strlen (home); + char *filename = xrealloc (home, homelen + sizeof xdefaults); + strcpy (filename + homelen, xdefaults); + db = XrmGetFileDatabase (filename); + xfree (filename); } #ifdef HAVE_XSCREENRESOURCESTRING @@ -380,24 +378,23 @@ static XrmDatabase get_environ_db (void) { XrmDatabase db; - char *p; - char *path = 0; + char *p = getenv ("XENVIRONMENT"); + char *filename = 0; - if ((p = getenv ("XENVIRONMENT")) == NULL) + if (!p) { - static char const xdefaults[] = ".Xdefaults-"; char *home = gethomedir (); - char const *host = SSDATA (Vsystem_name); - ptrdiff_t pathsize = (strlen (home) + sizeof xdefaults - + SBYTES (Vsystem_name)); - path = xrealloc (home, pathsize); - strcat (strcat (path, xdefaults), host); - p = path; + ptrdiff_t homelen = strlen (home); + char *host = SSDATA (Vsystem_name); + ptrdiff_t filenamesize = (homelen + sizeof xdefaults + + SBYTES (Vsystem_name)); + p = filename = xrealloc (home, filenamesize); + strcpy (stpcpy (filename + homelen, xdefaults), host); } db = XrmGetFileDatabase (p); - xfree (path); + xfree (filename); return db; } diff --git a/src/xsmfns.c b/src/xsmfns.c index cd4f9ce..8a835cf 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -230,8 +230,7 @@ smc_save_yourself_CB (SmcConn smcConn, props[props_idx]->vals[vp_idx++].value = emacs_program; smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); - strcpy (smid_opt, SMID_OPT); - strcat (smid_opt, client_id); + strcpy (stpcpy (smid_opt, SMID_OPT), client_id); props[props_idx]->vals[vp_idx].length = strlen (smid_opt); props[props_idx]->vals[vp_idx++].value = smid_opt; @@ -242,8 +241,7 @@ smc_save_yourself_CB (SmcConn smcConn, if (cwd) { chdir_opt = xmalloc (strlen (CHDIR_OPT) + strlen (cwd) + 1); - strcpy (chdir_opt, CHDIR_OPT); - strcat (chdir_opt, cwd); + strcpy (stpcpy (chdir_opt, CHDIR_OPT), cwd); props[props_idx]->vals[vp_idx].length = strlen (chdir_opt); props[props_idx]->vals[vp_idx++].value = chdir_opt; -- 1.9.3