emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master cffa570: etags: remove some arbitrary limits


From: Paul Eggert
Subject: master cffa570: etags: remove some arbitrary limits
Date: Tue, 26 Nov 2019 16:57:05 -0500 (EST)

branch: master
commit cffa5703b95fba3624dc54db5e693bae559eac5f
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    etags: remove some arbitrary limits
    
    etags had undefined behavior if input files, lines, tags, etc.,
    had more than INT_MAX bytes.  Clean up the usage of integer types
    to fix the overflow errors I found.
    * admin/merge-gnulib (GNULIB_MODULES): Add mempcpy.
    * lib-src/etags.c: Include inttypes.h, intprops.h.
    (memcpyz): New function.  Use it to simplify several occurrences
    of memcpy followed by storing a trailing '\0'.
    (xnew): Use xnmalloc, to catch overflow on integer multiplication.
    (xrnew): Change last arg to multiplier.  The type is not needed.
    All callers changed.
    (node, lineno, charno, linecharno, invalidcharno, make_tag):
    (pfnote, add_node, number_len, C_symtype, lbz, Makefile_targets)
    (readline):
    Use intmax_t for line numbers and character positions, instead of
    int or long.
    (linebuffer, make_tag, pfnote, total_size_of_entries, put_entry)
    (in_word_set, C_symtype, token, cstack, pushclass_above):
    (popclass_above, write_classname, consider_token, C_entries)
    (Ruby_functions, Makefile_targets, Lua_functions, TeX_commands)
    (TeX_decode_env, erlang_func, erlang_attribute, erlang_atom)
    (substitute, regex_tag_multiline, nocase_tail, readline_interval)
    (readline, savenstr, concat, etags_getcwd, relative_filename)
    (linebuffer_setlen):
    Use ptrdiff_t for object sizes, instead of int or long or unsigned
    or size_t.
    (write_classname, C_entries):
    Avoid sprintf, as the result could exceed INT_MAX bytes
    and then behavior goes haywire.
    (main): Use int, instead of unsigned, for argv counts.
    (get_language_from_filename): Use bool for boolean.
    (Ruby_functions): Prefer strcpy to memcpy when copying "=".
    (linebuffer_setlen): Use ‘if’ instead of ‘while’.
    (memory_full, xnmalloc, xnrealloc): New functions.
    (xmalloc): Use memory_full, and take a ptrdiff_t instead of a size_t.
    (xrealloc): Remove; no longer needed.
    * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
    * lib/mempcpy.c, m4/mempcpy.m4: New files, copied from Gnulib.
---
 admin/merge-gnulib |   2 +-
 lib-src/etags.c    | 404 ++++++++++++++++++++++++++++-------------------------
 lib/gnulib.mk.in   |  12 ++
 lib/mempcpy.c      |  28 ++++
 m4/gnulib-comp.m4  |   9 ++
 m4/mempcpy.m4      |  26 ++++
 6 files changed, 287 insertions(+), 194 deletions(-)

diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 50b0c76..5192916 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -37,7 +37,7 @@ GNULIB_MODULES='
   filemode filevercmp flexmember fpieee fstatat fsusage fsync
   getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
   ieee754-h ignore-value intprops largefile lstat
-  manywarnings memmem-simple memrchr minmax mkostemp mktime nstrftime
+  manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime nstrftime
   pathmax pipe2 pselect pthread_sigmask putenv
   qcopy-acl readlink readlinkat regex
   sig2str socklen stat-time std-gnu11 stdalign stddef stdio
diff --git a/lib-src/etags.c b/lib-src/etags.c
index 6409407..0665cb0 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -114,6 +114,7 @@ char pot_etags_version[] = "@(#) pot revision number is 
17.38.1.4";
 # define O_CLOEXEC O_NOINHERIT
 #endif /* WINDOWSNT */
 
+#include <inttypes.h>
 #include <limits.h>
 #include <unistd.h>
 #include <stdarg.h>
@@ -123,6 +124,7 @@ char pot_etags_version[] = "@(#) pot revision number is 
17.38.1.4";
 #include <errno.h>
 #include <fcntl.h>
 #include <binary-io.h>
+#include <intprops.h>
 #include <unlocked-io.h>
 #include <c-ctype.h>
 #include <c-strcase.h>
@@ -141,6 +143,14 @@ char pot_etags_version[] = "@(#) pot revision number is 
17.38.1.4";
 # define CTAGS false
 #endif
 
+/* Copy to DEST from SRC (containing LEN bytes), and append a NUL byte.  */
+static void
+memcpyz (void *dest, void const *src, ptrdiff_t len)
+{
+  char *e = mempcpy (dest, src, len);
+  *e = '\0';
+}
+
 static bool
 streq (char const *s, char const *t)
 {
@@ -235,11 +245,11 @@ endtoken (unsigned char c)
 /*
  *     xnew, xrnew -- allocate, reallocate storage
  *
- * SYNOPSIS:   Type *xnew (int n, Type);
- *             void xrnew (OldPointer, int n, Type);
+ * SYNOPSIS:   Type *xnew (ptrdiff_t n, Type);
+ *             void xrnew (OldPointer, ptrdiff_t n, int multiplier);
  */
-#define xnew(n, Type)      ((Type *) xmalloc ((n) * sizeof (Type)))
-#define xrnew(op, n, Type) ((op) = (Type *) xrealloc (op, (n) * sizeof (Type)))
+#define xnew(n, Type) ((Type *) xnmalloc (n, sizeof (Type)))
+#define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
 
 typedef void Lang_function (FILE *);
 
@@ -282,8 +292,8 @@ typedef struct node_st
   bool valid;                  /* write this tag on the tag file */
   bool is_func;                        /* function tag: use regexp in CTAGS 
mode */
   bool been_warned;            /* warning already given for duplicated tag */
-  int lno;                     /* line number tag is on */
-  long cno;                    /* character number line starts on */
+  intmax_t lno;                        /* line number tag is on */
+  intmax_t cno;                        /* character number line starts on */
 } node;
 
 /*
@@ -295,8 +305,8 @@ typedef struct node_st
  */
 typedef struct
 {
-  long size;
-  int len;
+  ptrdiff_t size;
+  ptrdiff_t len;
   char *buffer;
 } linebuffer;
 
@@ -365,7 +375,7 @@ static void just_read_file (FILE *);
 
 static language *get_language_from_langname (const char *);
 static void readline (linebuffer *, FILE *);
-static long readline_internal (linebuffer *, FILE *, char const *);
+static ptrdiff_t readline_internal (linebuffer *, FILE *, char const *);
 static bool nocase_tail (const char *);
 static void get_tag (char *, char **);
 static void get_lispy_tag (char *);
@@ -385,7 +395,7 @@ static void process_file (FILE *, char *, language *);
 static void find_entries (FILE *);
 static void free_tree (node *);
 static void free_fdesc (fdesc *);
-static void pfnote (char *, bool, char *, int, int, long);
+static void pfnote (char *, bool, char *, ptrdiff_t, intmax_t, intmax_t);
 static void invalidate_nodes (fdesc *, node **);
 static void put_entries (node *);
 
@@ -393,7 +403,7 @@ static char *concat (const char *, const char *, const char 
*);
 static char *skip_spaces (char *);
 static char *skip_non_spaces (char *);
 static char *skip_name (char *);
-static char *savenstr (const char *, int);
+static char *savenstr (const char *, ptrdiff_t);
 static char *savestr (const char *);
 static char *etags_getcwd (void);
 static char *relative_filename (char *, char *);
@@ -403,9 +413,11 @@ static bool filename_is_absolute (char *f);
 static void canonicalize_filename (char *);
 static char *etags_mktmp (void);
 static void linebuffer_init (linebuffer *);
-static void linebuffer_setlen (linebuffer *, int);
-static void *xmalloc (size_t);
-static void *xrealloc (void *, size_t);
+static void linebuffer_setlen (linebuffer *, ptrdiff_t);
+static void *xmalloc (ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1));
+static void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2));
+static void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
+  ATTRIBUTE_ALLOC_SIZE ((2,3));
 
 
 static char searchar = '/';    /* use /.../ searches */
@@ -420,12 +432,12 @@ static ptrdiff_t whatlen_max;     /* maximum length of 
any 'what' member */
 static fdesc *fdhead;          /* head of file description list */
 static fdesc *curfdp;          /* current file description */
 static char *infilename;       /* current input file name */
-static int lineno;             /* line number of current line */
-static long charno;            /* current character number */
-static long linecharno;                /* charno of start of current line */
+static intmax_t lineno;                /* line number of current line */
+static intmax_t charno;                /* current character number */
+static intmax_t linecharno;    /* charno of start of current line */
 static char *dbp;              /* pointer to start of current tag */
 
-static const int invalidcharno = -1;
+static intmax_t const invalidcharno = -1;
 
 static node *nodehead;         /* the head of the binary tree of tags */
 static node *last_node;                /* the last node created */
@@ -1070,7 +1082,7 @@ int
 main (int argc, char **argv)
 {
   int i;
-  unsigned int nincluded_files;
+  int nincluded_files;
   char **included_files;
   argument *argbuffer;
   int current_arg, file_count;
@@ -1484,7 +1496,7 @@ get_language_from_interpreter (char *interpreter)
  * Return a language given the file name.
  */
 static language *
-get_language_from_filename (char *file, int case_sensitive)
+get_language_from_filename (char *file, bool case_sensitive)
 {
   language *lang;
   const char **name, **ext, *suffix;
@@ -1918,26 +1930,26 @@ find_entries (FILE *inf)
  */
 static void
 make_tag (const char *name,    /* tag name, or NULL if unnamed */
-         int namelen,          /* tag length */
+         ptrdiff_t namelen,    /* tag length */
          bool is_func,         /* tag is a function */
          char *linestart,      /* start of the line where tag is */
-         int linelen,          /* length of the line where tag is */
-         int lno,              /* line number */
-         long int cno)         /* character number */
+         ptrdiff_t linelen,    /* length of the line where tag is */
+         intmax_t lno,         /* line number */
+         intmax_t cno)         /* character number */
 {
   bool named = (name != NULL && namelen > 0);
   char *nname = NULL;
 
   if (debug)
-    fprintf (stderr, "%s on %s:%d: %s\n",
+    fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
             named ? name : "(unnamed)", curfdp->taggedfname, lno, linestart);
 
   if (!CTAGS && named)         /* maybe set named to false */
     /* Let's try to make an implicit tag name, that is, create an unnamed tag
        such that etags.el can guess a name from it. */
     {
-      int i;
-      register const char *cp = name;
+      ptrdiff_t i;
+      const char *cp = name;
 
       for (i = 0; i < namelen; i++)
        if (notinname (*cp++))
@@ -1963,8 +1975,8 @@ make_tag (const char *name,       /* tag name, or NULL if 
unnamed */
 
 /* Record a tag. */
 static void
-pfnote (char *name, bool is_func, char *linestart, int linelen, int lno,
-       long int cno)
+pfnote (char *name, bool is_func, char *linestart, ptrdiff_t linelen,
+       intmax_t lno, intmax_t cno)
                                /* tag name, or NULL if unnamed */
                                /* tag is a function */
                                /* start of the line where tag is */
@@ -2197,7 +2209,8 @@ add_node (node *np, node **cur_node_p)
                  if (!no_warnings)
                    {
                      fprintf (stderr,
-                              "Duplicate entry in file %s, line %d: %s\n",
+                              ("Duplicate entry in file %s, "
+                               "line %"PRIdMAX": %s\n"),
                               np->fdp->infname, lineno, np->name);
                      fprintf (stderr, "Second entry ignored\n");
                    }
@@ -2293,12 +2306,12 @@ invalidate_nodes (fdesc *badfdp, node **npp)
 }
 
 
-static int total_size_of_entries (node *);
-static int number_len (long) ATTRIBUTE_CONST;
+static ptrdiff_t total_size_of_entries (node *);
+static int number_len (intmax_t) ATTRIBUTE_CONST;
 
 /* Length of a non-negative number's decimal representation. */
 static int
-number_len (long int num)
+number_len (intmax_t num)
 {
   int len = 1;
   while ((num /= 10) > 0)
@@ -2312,10 +2325,10 @@ number_len (long int num)
  * This count is irrelevant with etags.el since emacs 19.34 at least,
  * but is still supplied for backward compatibility.
  */
-static int
-total_size_of_entries (register node *np)
+static ptrdiff_t
+total_size_of_entries (node *np)
 {
-  register int total = 0;
+  ptrdiff_t total = 0;
 
   for (; np != NULL; np = np->right)
     if (np->valid)
@@ -2323,7 +2336,7 @@ total_size_of_entries (register node *np)
        total += strlen (np->regex) + 1;                /* pat\177 */
        if (np->name != NULL)
          total += strlen (np->name) + 1;               /* name\001 */
-       total += number_len ((long) np->lno) + 1;       /* lno, */
+       total += number_len (np->lno) + 1;              /* lno, */
        if (np->cno != invalidcharno)                   /* cno */
          total += number_len (np->cno);
        total += 1;                                     /* newline */
@@ -2347,7 +2360,7 @@ put_entry (node *np)
          if (fdp != np->fdp)
            {
              fdp = np->fdp;
-             fprintf (tagf, "\f\n%s,%d\n",
+             fprintf (tagf, "\f\n%s,%"PRIdPTR"\n",
                       fdp->taggedfname, total_size_of_entries (np));
              fdp->written = true;
            }
@@ -2358,9 +2371,9 @@ put_entry (node *np)
              fputs (np->name, tagf);
              fputc ('\001', tagf);
            }
-         fprintf (tagf, "%d,", np->lno);
+         fprintf (tagf, "%"PRIdMAX",", np->lno);
          if (np->cno != invalidcharno)
-           fprintf (tagf, "%ld", np->cno);
+           fprintf (tagf, "%"PRIdMAX, np->cno);
          fputs ("\n", tagf);
        }
       else
@@ -2372,10 +2385,10 @@ put_entry (node *np)
          if (cxref_style)
            {
              if (vgrind_style)
-               fprintf (stdout, "%s %s %d\n",
+               fprintf (stdout, "%s %s %"PRIdMAX"\n",
                         np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
              else
-               fprintf (stdout, "%-16s %3d %-16s %s\n",
+               fprintf (stdout, "%-16s %3"PRIdMAX" %-16s %s\n",
                         np->name, np->lno, np->fdp->taggedfname, np->regex);
            }
          else
@@ -2397,7 +2410,7 @@ put_entry (node *np)
                }
              else
                {               /* anything else; text pattern inadequate */
-                 fprintf (tagf, "%d", np->lno);
+                 fprintf (tagf, "%"PRIdMAX, np->lno);
                }
              putc ('\n', tagf);
            }
@@ -2591,7 +2604,7 @@ hash (const char *str, int len)
 }
 
 static struct C_stab_entry *
-in_word_set (register const char *str, register unsigned int len)
+in_word_set (const char *str, ptrdiff_t len)
 {
   enum
     {
@@ -2658,9 +2671,9 @@ in_word_set (register const char *str, register unsigned 
int len)
 /*%>*/
 
 static enum sym_type
-C_symtype (char *str, int len, int c_ext)
+C_symtype (char *str, ptrdiff_t len, int c_ext)
 {
-  register struct C_stab_entry *se = in_word_set (str, len);
+  struct C_stab_entry *se = in_word_set (str, len);
 
   if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
     return st_none;
@@ -2770,8 +2783,8 @@ static enum
 static struct tok
 {
   char *line;                  /* string containing the token */
-  int offset;                  /* where the token starts in LINE */
-  int length;                  /* token length */
+  ptrdiff_t offset;            /* where the token starts in LINE */
+  ptrdiff_t length;            /* token length */
   /*
     The previous members can be used to pass strings around for generic
     purposes.  The following ones specifically refer to creating tags.  In this
@@ -2782,23 +2795,23 @@ static struct tok
                                   invalidated whenever a state machine is
                                   reset prematurely */
   bool named;                  /* create a named tag */
-  int lineno;                  /* source line number of tag */
-  long linepos;                        /* source char number of tag */
+  intmax_t lineno;             /* source line number of tag */
+  intmax_t linepos;            /* source char number of tag */
 } token;                       /* latest token read */
 
 /*
  * Variables and functions for dealing with nested structures.
  * Idea by Mykola Dzyuba <address@hidden> (2001)
  */
-static void pushclass_above (int, char *, int);
-static void popclass_above (int);
+static void pushclass_above (ptrdiff_t, char *, ptrdiff_t);
+static void popclass_above (ptrdiff_t);
 static void write_classname (linebuffer *, const char *qualifier);
 
 static struct {
   char **cname;                        /* nested class names */
-  int *bracelev;               /* nested class brace level */
-  int nl;                      /* class nesting level (elements used) */
-  int size;                    /* length of the array */
+  ptrdiff_t *bracelev;         /* nested class brace level */
+  ptrdiff_t nl;                        /* class nesting level (elements used) 
*/
+  ptrdiff_t size;              /* length of the array */
 } cstack;                      /* stack for nested declaration tags */
 /* Current struct nesting depth (namespace, class, struct, union, enum). */
 #define nestlev                (cstack.nl)
@@ -2807,17 +2820,17 @@ static struct {
                         && bracelev == cstack.bracelev[nestlev-1] + 1)
 
 static void
-pushclass_above (int bracelev, char *str, int len)
+pushclass_above (ptrdiff_t bracelev, char *str, ptrdiff_t len)
 {
-  int nl;
+  ptrdiff_t nl;
 
   popclass_above (bracelev);
   nl = cstack.nl;
   if (nl >= cstack.size)
     {
-      int size = cstack.size *= 2;
-      xrnew (cstack.cname, size, char *);
-      xrnew (cstack.bracelev, size, int);
+      xrnew (cstack.cname, cstack.size, 2);
+      xrnew (cstack.bracelev, cstack.size, 2);
+      cstack.size *= 2;
     }
   assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
   cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
@@ -2826,11 +2839,9 @@ pushclass_above (int bracelev, char *str, int len)
 }
 
 static void
-popclass_above (int bracelev)
+popclass_above (ptrdiff_t bracelev)
 {
-  int nl;
-
-  for (nl = cstack.nl - 1;
+  for (ptrdiff_t nl = cstack.nl - 1;
        nl >= 0 && cstack.bracelev[nl] >= bracelev;
        nl--)
     {
@@ -2842,8 +2853,7 @@ popclass_above (int bracelev)
 static void
 write_classname (linebuffer *cn, const char *qualifier)
 {
-  int i, len;
-  int qlen = strlen (qualifier);
+  ptrdiff_t len;
 
   if (cstack.nl == 0 || cstack.cname[0] == NULL)
     {
@@ -2857,18 +2867,22 @@ write_classname (linebuffer *cn, const char *qualifier)
       linebuffer_setlen (cn, len);
       strcpy (cn->buffer, cstack.cname[0]);
     }
-  for (i = 1; i < cstack.nl; i++)
+  for (ptrdiff_t i = 1; i < cstack.nl; i++)
     {
       char *s = cstack.cname[i];
       if (s == NULL)
        continue;
-      linebuffer_setlen (cn, len + qlen + strlen (s));
-      len += sprintf (cn->buffer + len, "%s%s", qualifier, s);
+      int qlen = strlen (qualifier);
+      ptrdiff_t slen = strlen (s);
+      linebuffer_setlen (cn, len + qlen + slen);
+      memcpyz (stpcpy (cn->buffer + len, qualifier), s, slen);
+      len += qlen + slen;
     }
 }
 
 
-static bool consider_token (char *, int, int, int *, int, int, bool *);
+static bool consider_token (char *, ptrdiff_t, int, int *,
+                           ptrdiff_t, ptrdiff_t, bool *);
 static void make_C_tag (bool);
 
 /*
@@ -2889,8 +2903,8 @@ static void make_C_tag (bool);
  */
 
 static bool
-consider_token (char *str, int len, int c, int *c_extp,
-               int bracelev, int parlev, bool *is_func_or_var)
+consider_token (char *str, ptrdiff_t len, int c, int *c_extp,
+               ptrdiff_t bracelev, ptrdiff_t parlev, bool *is_func_or_var)
                                /* IN: token pointer */
                                /* IN: token length */
                                /* IN: first char after the token */
@@ -2903,7 +2917,7 @@ consider_token (char *str, int len, int c, int *c_extp,
      structtype is the type of the preceding struct-like keyword, and
      structbracelev is the brace level where it has been seen. */
   static enum sym_type structtype;
-  static int structbracelev;
+  static ptrdiff_t structbracelev;
   static enum sym_type toktype;
 
 
@@ -3098,8 +3112,7 @@ consider_token (char *str, int len, int c, int *c_extp,
           fvdef = fvnone;
           objdef = omethodtag;
           linebuffer_setlen (&token_name, len);
-          memcpy (token_name.buffer, str, len);
-          token_name.buffer[len] = '\0';
+          memcpyz (token_name.buffer, str, len);
           return true;
         }
        return false;
@@ -3113,11 +3126,10 @@ consider_token (char *str, int len, int c, int *c_extp,
           objdef = omethodtag;
           if (class_qualify)
             {
-              int oldlen = token_name.len;
+              ptrdiff_t oldlen = token_name.len;
               fvdef = fvnone;
               linebuffer_setlen (&token_name, oldlen + len);
-              memcpy (token_name.buffer + oldlen, str, len);
-              token_name.buffer[oldlen + len] = '\0';
+              memcpyz (token_name.buffer + oldlen, str, len);
             }
           return true;
         }
@@ -3228,7 +3240,7 @@ consider_token (char *str, int len, int c, int *c_extp,
  */
 static struct
 {
-  long linepos;
+  intmax_t linepos;
   linebuffer lb;
 } lbs[2];
 
@@ -3302,19 +3314,19 @@ C_entries (int c_ext, FILE *inf)
                                        /* extension of C */
                                        /* input file */
 {
-  register char c;             /* latest char read; '\0' for end of line */
-  register char *lp;           /* pointer one beyond the character `c' */
-  int curndx, newndx;          /* indices for current and new lb */
-  register int tokoff;         /* offset in line of start of current token */
-  register int toklen;         /* length of current token */
+  char c;                      /* latest char read; '\0' for end of line */
+  char *lp;                    /* pointer one beyond the character `c' */
+  bool curndx, newndx;         /* indices for current and new lb */
+  ptrdiff_t tokoff;            /* offset in line of start of current token */
+  ptrdiff_t toklen;            /* length of current token */
   const char *qualifier;        /* string used to qualify names */
   int qlen;                    /* length of qualifier */
-  int bracelev;                        /* current brace level */
-  int bracketlev;              /* current bracket level */
-  int parlev;                  /* current parenthesis level */
-  int attrparlev;              /* __attribute__ parenthesis level */
-  int templatelev;             /* current template level */
-  int typdefbracelev;          /* bracelev where a typedef struct body begun */
+  ptrdiff_t bracelev;          /* current brace level */
+  ptrdiff_t bracketlev;                /* current bracket level */
+  ptrdiff_t parlev;            /* current parenthesis level */
+  ptrdiff_t attrparlev;                /* __attribute__ parenthesis level */
+  ptrdiff_t templatelev;       /* current template level */
+  ptrdiff_t typdefbracelev;    /* bracelev where a typedef struct body begun */
   bool incomm, inquote, inchar, quotednl, midtoken;
   bool yacc_rules;             /* in the rules part of a yacc file */
   struct tok savetoken = {0};  /* token saved during preprocessor handling */
@@ -3327,7 +3339,7 @@ C_entries (int c_ext, FILE *inf)
       cstack.size = (DEBUG) ? 1 : 4;
       cstack.nl = 0;
       cstack.cname = xnew (cstack.size, char *);
-      cstack.bracelev = xnew (cstack.size, int);
+      cstack.bracelev = xnew (cstack.size, ptrdiff_t);
     }
 
   tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
@@ -3579,20 +3591,19 @@ C_entries (int c_ext, FILE *inf)
                            {
                              if (class_qualify)
                                {
-                                 int len;
                                  write_classname (&token_name, qualifier);
-                                 len = token_name.len;
+                                 ptrdiff_t len = token_name.len;
                                  linebuffer_setlen (&token_name,
                                                     len + qlen + toklen);
-                                 sprintf (token_name.buffer + len, "%s%.*s",
-                                          qualifier, toklen,
-                                          newlb.buffer + tokoff);
+                                 memcpyz (stpcpy (token_name.buffer + len,
+                                                  qualifier),
+                                          newlb.buffer + tokoff, toklen);
                                }
                              else
                                {
                                  linebuffer_setlen (&token_name, toklen);
-                                 sprintf (token_name.buffer, "%.*s",
-                                          toklen, newlb.buffer + tokoff);
+                                 memcpyz (token_name.buffer,
+                                          newlb.buffer + tokoff, toklen);
                                }
                              token.named = true;
                            }
@@ -3601,17 +3612,19 @@ C_entries (int c_ext, FILE *inf)
                            {
                              if (class_qualify)
                                {
-                                 int len = strlen (objtag) + 2 + toklen;
+                                 ptrdiff_t len = strlen (objtag) + 2 + toklen;
                                  linebuffer_setlen (&token_name, len);
-                                 sprintf (token_name.buffer, "%s(%.*s)",
-                                          objtag, toklen,
-                                          newlb.buffer + tokoff);
+                                 char *p1 = stpcpy (token_name.buffer, objtag);
+                                 char *p2 = stpcpy (p1, "(");
+                                 char *p3 = mempcpy (p2, newlb.buffer + tokoff,
+                                                     toklen);
+                                 strcpy (p3, ")");
                                }
                              else
                                {
                                  linebuffer_setlen (&token_name, toklen);
-                                 sprintf (token_name.buffer, "%.*s",
-                                          toklen, newlb.buffer + tokoff);
+                                 memcpyz (token_name.buffer,
+                                          newlb.buffer + tokoff, toklen);
                                }
                              token.named = true;
                            }
@@ -3625,8 +3638,8 @@ C_entries (int c_ext, FILE *inf)
                            /* GNU DEFUN and similar macros */
                            {
                              bool defun = (newlb.buffer[tokoff] == 'F');
-                             int off = tokoff;
-                             int len = toklen;
+                             ptrdiff_t off = tokoff;
+                             ptrdiff_t len = toklen;
 
                              if (defun)
                                {
@@ -3635,9 +3648,8 @@ C_entries (int c_ext, FILE *inf)
 
                                  /* First, tag it as its C name */
                                  linebuffer_setlen (&token_name, toklen);
-                                 memcpy (token_name.buffer,
-                                         newlb.buffer + tokoff, toklen);
-                                 token_name.buffer[toklen] = '\0';
+                                 memcpyz (token_name.buffer,
+                                          newlb.buffer + tokoff, toklen);
                                  token.named = true;
                                  token.lineno = lineno;
                                  token.offset = tokoff;
@@ -3650,9 +3662,8 @@ C_entries (int c_ext, FILE *inf)
                              /* Rewrite the tag so that emacs lisp DEFUNs
                                 can be found also by their elisp name */
                              linebuffer_setlen (&token_name, len);
-                             memcpy (token_name.buffer,
-                                     newlb.buffer + off, len);
-                             token_name.buffer[len] = '\0';
+                             memcpyz (token_name.buffer,
+                                      newlb.buffer + off, len);
                              if (defun)
                                while (--len >= 0)
                                  if (token_name.buffer[len] == '_')
@@ -3662,9 +3673,8 @@ C_entries (int c_ext, FILE *inf)
                          else
                            {
                              linebuffer_setlen (&token_name, toklen);
-                             memcpy (token_name.buffer,
-                                     newlb.buffer + tokoff, toklen);
-                             token_name.buffer[toklen] = '\0';
+                             memcpyz (token_name.buffer,
+                                      newlb.buffer + tokoff, toklen);
                              /* Name macros and members. */
                              token.named = (structdef == stagseen
                                             || typdef == ttypeseen
@@ -3790,7 +3800,7 @@ C_entries (int c_ext, FILE *inf)
              objdef = omethodcolon;
              if (class_qualify)
                {
-                 int toklen = token_name.len;
+                 ptrdiff_t toklen = token_name.len;
                  linebuffer_setlen (&token_name, toklen + 1);
                  strcpy (token_name.buffer + toklen, ":");
                }
@@ -4061,7 +4071,7 @@ C_entries (int c_ext, FILE *inf)
                    }
                  if (uqname > token_name.buffer)
                    {
-                     int uqlen = strlen (uqname);
+                     ptrdiff_t uqlen = strlen (uqname);
                      linebuffer_setlen (&token_name, uqlen);
                      memmove (token_name.buffer, uqname, uqlen + 1);
                    }
@@ -4979,12 +4989,11 @@ Ruby_functions (FILE *inf)
                        size_t name_len = cp - np + 1;
                        char *wr_name = xnew (name_len + 1, char);
 
-                       memcpy (wr_name, np, name_len - 1);
-                       memcpy (wr_name + name_len - 1, "=", 2);
+                       strcpy (mempcpy (wr_name, np, name_len - 1), "=");
                        pfnote (wr_name, true, lb.buffer, cp - lb.buffer + 1,
                                lineno, linecharno);
                        if (debug)
-                         fprintf (stderr, "%s on %s:%d: %s\n", wr_name,
+                         fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n", wr_name,
                                   curfdp->taggedfname, lineno, lb.buffer);
                        continuation = false;
                      }
@@ -5178,8 +5187,8 @@ static void
 Pascal_functions (FILE *inf)
 {
   linebuffer tline;            /* mostly copied from C_entries */
-  long save_lcno;
-  int save_lineno, namelen, taglen;
+  intmax_t save_lcno, save_lineno;
+  ptrdiff_t namelen, taglen;
   char c, *name;
 
   bool                         /* each of these flags is true if: */
@@ -5455,7 +5464,7 @@ Lua_functions (FILE *inf)
          if (tp_dot || tp_colon)
            {
              char *p = tp_dot > tp_colon ? tp_dot : tp_colon;
-             int len_add = p - tag_name + 1;
+             ptrdiff_t len_add = p - tag_name + 1;
 
              get_tag (bp + len_add, NULL);
            }
@@ -5656,7 +5665,7 @@ TeX_commands (FILE *inf)
            if (strneq (cp, key->buffer, key->len))
              {
                char *p;
-               int namelen, linelen;
+               ptrdiff_t namelen, linelen;
                bool opgrp = false;
 
                cp = skip_spaces (cp + key->len);
@@ -5693,8 +5702,8 @@ TeX_commands (FILE *inf)
 static void
 TEX_decode_env (const char *evarname, const char *defenv)
 {
-  register const char *env, *p;
-  int i, len;
+  const char *env, *p;
+  ptrdiff_t len;
 
   /* Append default string to environment. */
   env = getenv (evarname);
@@ -5711,7 +5720,7 @@ TEX_decode_env (const char *evarname, const char *defenv)
 
   /* Unpack environment string into token table. Be careful about */
   /* zero-length strings (leading ':', "::" and trailing ':') */
-  for (i = 0; *env != '\0';)
+  for (ptrdiff_t i = 0; *env != '\0'; )
     {
       p = strchr (env, ':');
       if (!p)                  /* End of environment string. */
@@ -5811,8 +5820,7 @@ HTML_labels (FILE *inf)
                  for (end = dbp; *end != '\0' && intoken (*end); end++)
                    continue;
                linebuffer_setlen (&token_name, end - dbp);
-               memcpy (token_name.buffer, dbp, end - dbp);
-               token_name.buffer[end - dbp] = '\0';
+               memcpyz (token_name.buffer, dbp, end - dbp);
 
                dbp = end;
                intag = false;  /* we found what we looked for */
@@ -5906,11 +5914,10 @@ Prolog_functions (FILE *inf)
                 tags later.  */
              if (allocated <= len)
                {
-                 xrnew (last, len + 1, char);
+                 xrnew (last, len + 1, 1);
                  allocated = len + 1;
                }
-             memcpy (last, cp, len);
-             last[len] = '\0';
+             memcpyz (last, cp, len);
              lastlen = len;
            }
        }
@@ -6031,9 +6038,9 @@ prolog_atom (char *s, size_t pos)
  * Assumes that Erlang functions start at column 0.
  * Original code by Anders Lindgren (1996)
  */
-static int erlang_func (char *, char *, ptrdiff_t, ptrdiff_t *);
+static ptrdiff_t erlang_func (char *, char *, ptrdiff_t, ptrdiff_t *);
 static void erlang_attribute (char *);
-static int erlang_atom (char *);
+static ptrdiff_t erlang_atom (char *);
 
 static void
 Erlang_functions (FILE *inf)
@@ -6070,11 +6077,10 @@ Erlang_functions (FILE *inf)
                 tags later.  */
              if (allocated <= len)
                {
-                 xrnew (last, len + 1, char);
+                 xrnew (last, len + 1, 1);
                  allocated = len + 1;
                }
-             memcpy (last, cp + name_offset, len);
-             last[len] = '\0';
+             memcpyz (last, cp + name_offset, len);
              lastlen = len;
            }
        }
@@ -6093,7 +6099,7 @@ Erlang_functions (FILE *inf)
  * Return the size of the name of the function, or 0 if no function
  * was found.
  */
-static int
+static ptrdiff_t
 erlang_func (char *s, char *last, ptrdiff_t lastlen, ptrdiff_t *name_offset)
 {
   char *name = s;
@@ -6133,15 +6139,13 @@ static void
 erlang_attribute (char *s)
 {
   char *cp = s;
-  int pos;
-  int len;
 
   if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
       && *cp++ == '(')
     {
       cp = skip_spaces (cp);
-      len = erlang_atom (cp);
-      pos = cp + len - s;
+      ptrdiff_t len = erlang_atom (cp);
+      ptrdiff_t pos = cp + len - s;
       if (len > 0)
        {
          /* If the name is quoted, the quotes are not part of the name. */
@@ -6161,10 +6165,10 @@ erlang_attribute (char *s)
  * Consume an Erlang atom (or variable).
  * Return the number of bytes consumed, or -1 if there was an error.
  */
-static int
+static ptrdiff_t
 erlang_atom (char *s)
 {
-  int pos = 0;
+  ptrdiff_t pos = 0;
 
   if (c_isalpha (s[pos]) || s[pos] == '_')
     {
@@ -6437,10 +6441,9 @@ static char *
 substitute (char *in, char *out, struct re_registers *regs)
 {
   char *result, *t;
-  int size, dig, diglen;
 
   result = NULL;
-  size = strlen (out);
+  ptrdiff_t size = strlen (out);
 
   /* Pass 1: figure out how much to allocate by finding all \N strings. */
   if (out[size - 1] == '\\')
@@ -6450,8 +6453,8 @@ substitute (char *in, char *out, struct re_registers 
*regs)
        t = strchr (t + 2, '\\'))
     if (c_isdigit (t[1]))
       {
-       dig = t[1] - '0';
-       diglen = regs->end[dig] - regs->start[dig];
+       int dig = t[1] - '0';
+       ptrdiff_t diglen = regs->end[dig] - regs->start[dig];
        size += diglen - 2;
       }
     else
@@ -6464,8 +6467,8 @@ substitute (char *in, char *out, struct re_registers 
*regs)
   for (t = result; *out != '\0'; out++)
     if (*out == '\\' && c_isdigit (*++out))
       {
-       dig = *out - '0';
-       diglen = regs->end[dig] - regs->start[dig];
+       int dig = *out - '0';
+       ptrdiff_t diglen = regs->end[dig] - regs->start[dig];
        memcpy (t, in + regs->start[dig], diglen);
        t += diglen;
       }
@@ -6474,7 +6477,7 @@ substitute (char *in, char *out, struct re_registers 
*regs)
   *t = '\0';
 
   assert (t <= result + size);
-  assert (t - result == (int)strlen (result));
+  assert (t == result + strlen (result));
 
   return result;
 }
@@ -6511,7 +6514,7 @@ regex_tag_multiline (void)
 
   for (rp = p_head; rp != NULL; rp = rp->p_next)
     {
-      int match = 0;
+      ptrdiff_t match = 0;
 
       if (!rp->multi_line)
        continue;               /* skip normal regexps */
@@ -6572,7 +6575,7 @@ regex_tag_multiline (void)
                          charno - linecharno + 1, lineno, linecharno);
 
                  if (debug)
-                   fprintf (stderr, "%s on %s:%d: %s\n",
+                   fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
                             name ? name : "(unnamed)", curfdp->taggedfname,
                             lineno, buffer + linecharno);
                }
@@ -6589,7 +6592,7 @@ regex_tag_multiline (void)
 static bool
 nocase_tail (const char *cp)
 {
-  int len = 0;
+  ptrdiff_t len = 0;
 
   while (*cp != '\0' && c_tolower (*cp) == c_tolower (dbp[len]))
     cp++, len++;
@@ -6648,7 +6651,7 @@ get_lispy_tag (register char *bp)
  * If multi-line regular expressions are requested, each line read is
  * appended to `filebuf'.
  */
-static long
+static ptrdiff_t
 readline_internal (linebuffer *lbp, FILE *stream, char const *filename)
 {
   char *buffer = lbp->buffer;
@@ -6664,8 +6667,8 @@ readline_internal (linebuffer *lbp, FILE *stream, char 
const *filename)
       if (p == pend)
        {
          /* We're at the end of linebuffer: expand it. */
+         xrnew (buffer, lbp->size, 2);
          lbp->size *= 2;
-         xrnew (buffer, lbp->size, char);
          p += buffer - lbp->buffer;
          pend = buffer + lbp->size;
          lbp->buffer = buffer;
@@ -6702,13 +6705,12 @@ readline_internal (linebuffer *lbp, FILE *stream, char 
const *filename)
       while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
        {
          /* Expand filebuf. */
+         xrnew (filebuf.buffer, filebuf.size, 2);
          filebuf.size *= 2;
-         xrnew (filebuf.buffer, filebuf.size, char);
        }
-      memcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
-      filebuf.len += lbp->len;
-      filebuf.buffer[filebuf.len++] = '\n';
-      filebuf.buffer[filebuf.len] = '\0';
+      strcpy (mempcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len),
+             "\n");
+      filebuf.len += lbp->len + 1;
     }
 
   return lbp->len + chars_deleted;
@@ -6722,10 +6724,8 @@ readline_internal (linebuffer *lbp, FILE *stream, char 
const *filename)
 static void
 readline (linebuffer *lbp, FILE *stream)
 {
-  long result;
-
   linecharno = charno;         /* update global char number of line start */
-  result = readline_internal (lbp, stream, infilename); /* read line */
+  ptrdiff_t result = readline_internal (lbp, stream, infilename);
   lineno += 1;                 /* increment global line number */
   charno += result;            /* increment global char number */
 
@@ -6737,10 +6737,10 @@ readline (linebuffer *lbp, FILE *stream)
       /* Check whether this is a #line directive. */
       if (result > 12 && strneq (lbp->buffer, "#line ", 6))
        {
-         unsigned int lno;
+         intmax_t lno;
          int start = 0;
 
-         if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1
+         if (sscanf (lbp->buffer, "#line %"SCNdMAX" \"%n", &lno, &start) >= 1
              && start > 0)     /* double quote character found */
            {
              char *endp = lbp->buffer + start;
@@ -6850,7 +6850,7 @@ readline (linebuffer *lbp, FILE *stream)
     } /* if #line directives should be considered */
 
   {
-    int match;
+    ptrdiff_t match;
     regexp *rp;
     char *name;
 
@@ -6900,7 +6900,7 @@ readline (linebuffer *lbp, FILE *stream)
                  /* Force explicit tag name, if a name is there. */
                  pfnote (name, true, lbp->buffer, match, lineno, linecharno);
                  if (debug)
-                   fprintf (stderr, "%s on %s:%d: %s\n",
+                   fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
                             name ? name : "(unnamed)", curfdp->taggedfname,
                             lineno, lbp->buffer);
                }
@@ -6925,11 +6925,11 @@ savestr (const char *cp)
 }
 
 /*
- * Return a pointer to a space of size LEN+1 allocated with xnew where
- * the string CP has been copied for at most the first LEN characters.
+ * Return a pointer to a space of size LEN+1 allocated with xnew
+ * with a copy of CP (containing LEN bytes) followed by a NUL byte.
  */
 static char *
-savenstr (const char *cp, int len)
+savenstr (const char *cp, ptrdiff_t len)
 {
   char *dp = xnew (len + 1, char);
   dp[len] = '\0';
@@ -7013,13 +7013,9 @@ verror (char const *format, va_list ap)
 static char *
 concat (const char *s1, const char *s2, const char *s3)
 {
-  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+  ptrdiff_t len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
   char *result = xnew (len1 + len2 + len3 + 1, char);
-
-  strcpy (result, s1);
-  strcpy (result + len1, s2);
-  strcpy (result + len1 + len2, s3);
-
+  strcpy (stpcpy (stpcpy (result, s1), s2), s3);
   return result;
 }
 
@@ -7029,16 +7025,16 @@ concat (const char *s1, const char *s2, const char *s3)
 static char *
 etags_getcwd (void)
 {
-  int bufsize = 200;
+  ptrdiff_t bufsize = 200;
   char *path = xnew (bufsize, char);
 
   while (getcwd (path, bufsize) == NULL)
     {
       if (errno != ERANGE)
        pfatal ("getcwd");
-      bufsize *= 2;
       free (path);
-      path = xnew (bufsize, char);
+      path = xnmalloc (bufsize, 2 * sizeof *path);
+      bufsize *= 2;
     }
 
   canonicalize_filename (path);
@@ -7099,7 +7095,7 @@ static char *
 relative_filename (char *file, char *dir)
 {
   char *fp, *dp, *afn, *res;
-  int i;
+  ptrdiff_t i;
 
   /* Find the common root of file and dir (with a trailing slash). */
   afn = absolute_filename (file, cwd);
@@ -7282,32 +7278,54 @@ linebuffer_init (linebuffer *lbp)
 
 /* Set the minimum size of a string contained in a linebuffer. */
 static void
-linebuffer_setlen (linebuffer *lbp, int toksize)
+linebuffer_setlen (linebuffer *lbp, ptrdiff_t toksize)
 {
-  while (lbp->size <= toksize)
+  if (lbp->size <= toksize)
     {
-      lbp->size *= 2;
-      xrnew (lbp->buffer, lbp->size, char);
+      ptrdiff_t multiplier = toksize / lbp->size + 1;
+      xrnew (lbp->buffer, lbp->size, multiplier);
+      lbp->size *= multiplier;
     }
   lbp->len = toksize;
 }
 
-/* Like malloc but get fatal error if memory is exhausted. */
-static void * ATTRIBUTE_MALLOC
-xmalloc (size_t size)
+/* Memory allocators with a fatal error if memory is exhausted.  */
+
+static void
+memory_full (void)
+{
+  fatal ("virtual memory exhausted");
+}
+
+static void *
+xmalloc (ptrdiff_t size)
 {
+  if (SIZE_MAX < size)
+    memory_full ();
   void *result = malloc (size);
   if (result == NULL)
-    fatal ("virtual memory exhausted");
+    memory_full ();
   return result;
 }
 
 static void *
-xrealloc (void *ptr, size_t size)
+xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size)
 {
-  void *result = realloc (ptr, size);
-  if (result == NULL)
-    fatal ("virtual memory exhausted");
+  ptrdiff_t nbytes;
+  if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes))
+    memory_full ();
+  return xmalloc (nbytes);
+}
+
+static void *
+xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size)
+{
+  ptrdiff_t nbytes;
+  if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes) || SIZE_MAX < nbytes)
+    memory_full ();
+  void *result = realloc (pa, nbytes);
+  if (!result)
+    memory_full ();
   return result;
 }
 
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 9a2709c..8e3b569 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -116,6 +116,7 @@
 #  lstat \
 #  manywarnings \
 #  memmem-simple \
+#  mempcpy \
 #  memrchr \
 #  minmax \
 #  mkostemp \
@@ -2027,6 +2028,17 @@ EXTRA_libgnu_a_SOURCES += memmem.c
 endif
 ## end   gnulib module memmem-simple
 
+## begin gnulib module mempcpy
+ifeq (,$(OMIT_GNULIB_MODULE_mempcpy))
+
+
+EXTRA_DIST += mempcpy.c
+
+EXTRA_libgnu_a_SOURCES += mempcpy.c
+
+endif
+## end   gnulib module mempcpy
+
 ## begin gnulib module memrchr
 ifeq (,$(OMIT_GNULIB_MODULE_memrchr))
 
diff --git a/lib/mempcpy.c b/lib/mempcpy.c
new file mode 100644
index 0000000..d0220e1
--- /dev/null
+++ b/lib/mempcpy.c
@@ -0,0 +1,28 @@
+/* Copy memory area and return pointer after last written byte.
+   Copyright (C) 2003, 2007, 2009-2019 Free Software Foundation, Inc.
+
+   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, or (at your option)
+   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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <string.h>
+
+/* Copy N bytes of SRC to DEST, return pointer to bytes after the
+   last written byte.  */
+void *
+mempcpy (void *dest, const void *src, size_t n)
+{
+  return (char *) memcpy (dest, src, n) + n;
+}
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 625c221..baf9511 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -118,6 +118,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module malloca:
   # Code from module manywarnings:
   # Code from module memmem-simple:
+  # Code from module mempcpy:
   # Code from module memrchr:
   # Code from module minmax:
   # Code from module mkostemp:
@@ -327,6 +328,12 @@ AC_DEFUN([gl_INIT],
     AC_LIBOBJ([memmem])
   fi
   gl_STRING_MODULE_INDICATOR([memmem])
+  gl_FUNC_MEMPCPY
+  if test $HAVE_MEMPCPY = 0; then
+    AC_LIBOBJ([mempcpy])
+    gl_PREREQ_MEMPCPY
+  fi
+  gl_STRING_MODULE_INDICATOR([mempcpy])
   gl_FUNC_MEMRCHR
   if test $ac_cv_func_memrchr = no; then
     AC_LIBOBJ([memrchr])
@@ -954,6 +961,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/md5.c
   lib/md5.h
   lib/memmem.c
+  lib/mempcpy.c
   lib/memrchr.c
   lib/minmax.h
   lib/mkostemp.c
@@ -1094,6 +1102,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/mbstate_t.m4
   m4/md5.m4
   m4/memmem.m4
+  m4/mempcpy.m4
   m4/memrchr.m4
   m4/minmax.m4
   m4/mkostemp.m4
diff --git a/m4/mempcpy.m4 b/m4/mempcpy.m4
new file mode 100644
index 0000000..b6090eed
--- /dev/null
+++ b/m4/mempcpy.m4
@@ -0,0 +1,26 @@
+# mempcpy.m4 serial 11
+dnl Copyright (C) 2003-2004, 2006-2007, 2009-2019 Free Software Foundation,
+dnl 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_MEMPCPY],
+[
+  dnl Persuade glibc <string.h> to declare mempcpy().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  dnl The mempcpy() declaration in lib/string.in.h uses 'restrict'.
+  AC_REQUIRE([AC_C_RESTRICT])
+
+  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_CHECK_FUNCS([mempcpy])
+  if test $ac_cv_func_mempcpy = no; then
+    HAVE_MEMPCPY=0
+  fi
+])
+
+# Prerequisites of lib/mempcpy.c.
+AC_DEFUN([gl_PREREQ_MEMPCPY], [
+  :
+])



reply via email to

[Prev in Thread] Current Thread [Next in Thread]