diff options
-rw-r--r-- | support/ChangeLog | 10 | ||||
-rw-r--r-- | support/Makefile.am | 7 | ||||
-rw-r--r-- | support/Makefile.in | 33 | ||||
-rw-r--r-- | support/dynarray.h | 281 | ||||
-rw-r--r-- | support/malloc/dynarray_resize.c | 68 |
5 files changed, 392 insertions, 7 deletions
diff --git a/support/ChangeLog b/support/ChangeLog index 256e9782..7050d5e0 100644 --- a/support/ChangeLog +++ b/support/ChangeLog @@ -1,3 +1,13 @@ +2021-04-21 Arnold D. Robbins <arnold@skeeve.com> + + Don't depend upon GLIBC private interfaces. Thanks to + Dmitry V. Levin <ldv@altlinux.org> for the report. + + * Makefile.am (EXTRA_DIST): Add files in malloc directory. + (libsupport_a_SOURCES): Add malloc/dynarray_resize.c. + * dynarray.h: Copied from GNULIB. + * malloc/dynarray_resize.c: New file, from GNULIB. + 2021-03-29 Arnold D. Robbins <arnold@skeeve.com> Resettle after churn in GNULIB. diff --git a/support/Makefile.am b/support/Makefile.am index 1f42c83c..8aba8073 100644 --- a/support/Makefile.am +++ b/support/Makefile.am @@ -36,7 +36,9 @@ EXTRA_DIST = \ regcomp.c \ regex_internal.c \ regex_internal.h \ - regexec.c + regexec.c \ + malloc/dynarray.h \ + malloc/dynarray-skeleton.c # what to make and install noinst_LIBRARIES = libsupport.a @@ -56,7 +58,8 @@ libsupport_a_SOURCES = \ regex.c \ regex.h \ verify.h \ - xalloc.h + xalloc.h \ + malloc/dynarray_resize.c # For some make's, e.g. OpenBSD, that don't define this RM = rm -f diff --git a/support/Makefile.in b/support/Makefile.in index b982b8cc..810a887c 100644 --- a/support/Makefile.in +++ b/support/Makefile.in @@ -142,7 +142,7 @@ libsupport_a_AR = $(AR) $(ARFLAGS) libsupport_a_LIBADD = am_libsupport_a_OBJECTS = dfa.$(OBJEXT) getopt.$(OBJEXT) \ getopt1.$(OBJEXT) localeinfo.$(OBJEXT) random.$(OBJEXT) \ - regex.$(OBJEXT) + regex.$(OBJEXT) dynarray_resize.$(OBJEXT) libsupport_a_OBJECTS = $(am_libsupport_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -159,10 +159,15 @@ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__maybe_remake_depfiles = depfiles -am__depfiles_remade = ./$(DEPDIR)/dfa.Po ./$(DEPDIR)/getopt.Po \ +am__depfiles_remade = ./$(DEPDIR)/dfa.Po \ + ./$(DEPDIR)/dynarray_resize.Po ./$(DEPDIR)/getopt.Po \ ./$(DEPDIR)/getopt1.Po ./$(DEPDIR)/localeinfo.Po \ ./$(DEPDIR)/random.Po ./$(DEPDIR)/regex.Po am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) @@ -349,7 +354,9 @@ EXTRA_DIST = \ regcomp.c \ regex_internal.c \ regex_internal.h \ - regexec.c + regexec.c \ + malloc/dynarray.h \ + malloc/dynarray-skeleton.c # what to make and install @@ -370,7 +377,8 @@ libsupport_a_SOURCES = \ regex.c \ regex.h \ verify.h \ - xalloc.h + xalloc.h \ + malloc/dynarray_resize.c # For some make's, e.g. OpenBSD, that don't define this @@ -424,6 +432,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfa.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynarray_resize.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localeinfo.Po@am__quote@ # am--include-marker @@ -450,6 +459,20 @@ am--depfiles: $(am__depfiles_remade) @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +dynarray_resize.o: malloc/dynarray_resize.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynarray_resize.o -MD -MP -MF $(DEPDIR)/dynarray_resize.Tpo -c -o dynarray_resize.o `test -f 'malloc/dynarray_resize.c' || echo '$(srcdir)/'`malloc/dynarray_resize.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dynarray_resize.Tpo $(DEPDIR)/dynarray_resize.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='malloc/dynarray_resize.c' object='dynarray_resize.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dynarray_resize.o `test -f 'malloc/dynarray_resize.c' || echo '$(srcdir)/'`malloc/dynarray_resize.c + +dynarray_resize.obj: malloc/dynarray_resize.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynarray_resize.obj -MD -MP -MF $(DEPDIR)/dynarray_resize.Tpo -c -o dynarray_resize.obj `if test -f 'malloc/dynarray_resize.c'; then $(CYGPATH_W) 'malloc/dynarray_resize.c'; else $(CYGPATH_W) '$(srcdir)/malloc/dynarray_resize.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dynarray_resize.Tpo $(DEPDIR)/dynarray_resize.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='malloc/dynarray_resize.c' object='dynarray_resize.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dynarray_resize.obj `if test -f 'malloc/dynarray_resize.c'; then $(CYGPATH_W) 'malloc/dynarray_resize.c'; else $(CYGPATH_W) '$(srcdir)/malloc/dynarray_resize.c'; fi` + ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am @@ -575,6 +598,7 @@ clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/dfa.Po + -rm -f ./$(DEPDIR)/dynarray_resize.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getopt1.Po -rm -f ./$(DEPDIR)/localeinfo.Po @@ -626,6 +650,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/dfa.Po + -rm -f ./$(DEPDIR)/dynarray_resize.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getopt1.Po -rm -f ./$(DEPDIR)/localeinfo.Po diff --git a/support/dynarray.h b/support/dynarray.h index 01d85afa..9a8d3956 100644 --- a/support/dynarray.h +++ b/support/dynarray.h @@ -1 +1,280 @@ -// dummy for gawk +/* Type-safe arrays which grow dynamically. + Copyright 2021 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 of the License, 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/>. */ + +/* Written by Paul Eggert and Bruno Haible, 2021. */ + +#ifndef _GL_DYNARRAY_H +#define _GL_DYNARRAY_H + +/* Before including this file, you need to define: + + DYNARRAY_STRUCT + The struct tag of dynamic array to be defined. + + DYNARRAY_ELEMENT + The type name of the element type. Elements are copied + as if by memcpy, and can change address as the dynamic + array grows. + + DYNARRAY_PREFIX + The prefix of the functions which are defined. + + The following parameters are optional: + + DYNARRAY_ELEMENT_FREE + DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the + contents of elements. E is of type DYNARRAY_ELEMENT *. + + DYNARRAY_ELEMENT_INIT + DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new + element. E is of type DYNARRAY_ELEMENT *. + If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is + defined, new elements are automatically zero-initialized. + Otherwise, new elements have undefined contents. + + DYNARRAY_INITIAL_SIZE + The size of the statically allocated array (default: + at least 2, more elements if they fit into 128 bytes). + Must be a preprocessor constant. If DYNARRAY_INITIAL_SIZE is 0, + there is no statically allocated array at, and all non-empty + arrays are heap-allocated. + + DYNARRAY_FINAL_TYPE + The name of the type which holds the final array. If not + defined, is PREFIX##finalize not provided. DYNARRAY_FINAL_TYPE + must be a struct type, with members of type DYNARRAY_ELEMENT and + size_t at the start (in this order). + + These macros are undefined after this header file has been + included. + + The following types are provided (their members are private to the + dynarray implementation): + + struct DYNARRAY_STRUCT + + The following functions are provided: + */ + +/* Initialize a dynamic array object. This must be called before any + use of the object. */ +#if 0 +static void + DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *list); +#endif + +/* Deallocate the dynamic array and its elements. */ +#if 0 +static void + DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *list); +#endif + +/* Return true if the dynamic array is in an error state. */ +#if 0 +static bool + DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *list); +#endif + +/* Mark the dynamic array as failed. All elements are deallocated as + a side effect. */ +#if 0 +static void + DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *list); +#endif + +/* Return the number of elements which have been added to the dynamic + array. */ +#if 0 +static size_t + DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *list); +#endif + +/* Return a pointer to the first array element, if any. For a + zero-length array, the pointer can be NULL even though the dynamic + array has not entered the failure state. */ +#if 0 +static DYNARRAY_ELEMENT * + DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *list); +#endif + +/* Return a pointer one element past the last array element. For a + zero-length array, the pointer can be NULL even though the dynamic + array has not entered the failure state. */ +#if 0 +static DYNARRAY_ELEMENT * + DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *list); +#endif + +/* Return a pointer to the array element at INDEX. Terminate the + process if INDEX is out of bounds. */ +#if 0 +static DYNARRAY_ELEMENT * + DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *list, size_t index); +#endif + +/* Add ITEM at the end of the array, enlarging it by one element. + Mark *LIST as failed if the dynamic array allocation size cannot be + increased. */ +#if 0 +static void + DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *list, + DYNARRAY_ELEMENT item); +#endif + +/* Allocate a place for a new element in *LIST and return a pointer to + it. The pointer can be NULL if the dynamic array cannot be + enlarged due to a memory allocation failure. */ +#if 0 +static DYNARRAY_ELEMENT * + DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *list); +#endif + +/* Change the size of *LIST to SIZE. If SIZE is larger than the + existing size, new elements are added (which can be initialized). + Otherwise, the list is truncated, and elements are freed. Return + false on memory allocation failure (and mark *LIST as failed). */ +#if 0 +static bool + DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *list, size_t size); +#endif + +/* Remove the last element of LIST if it is present. */ +#if 0 +static void + DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *list); +#endif + +/* Remove all elements from the list. The elements are freed, but the + list itself is not. */ +#if 0 +static void + DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *list); +#endif + +#if defined DYNARRAY_FINAL_TYPE +/* Transfer the dynamic array to a permanent location at *RESULT. + Returns true on success on false on allocation failure. In either + case, *LIST is re-initialized and can be reused. A NULL pointer is + stored in *RESULT if LIST refers to an empty list. On success, the + pointer in *RESULT is heap-allocated and must be deallocated using + free. */ +#if 0 +static bool + DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list, + DYNARRAY_FINAL_TYPE *result); +#endif +#else /* !defined DYNARRAY_FINAL_TYPE */ +/* Transfer the dynamic array to a heap-allocated array and return a + pointer to it. The pointer is NULL if memory allocation fails, or + if the array is empty, so this function should be used only for + arrays which are known not be empty (usually because they always + have a sentinel at the end). If LENGTHP is not NULL, the array + length is written to *LENGTHP. *LIST is re-initialized and can be + reused. */ +#if 0 +static DYNARRAY_ELEMENT * + DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list, + size_t *lengthp); +#endif +#endif + +/* A minimal example which provides a growing list of integers can be + defined like this: + + struct int_array + { + // Pointer to result array followed by its length, + // as required by DYNARRAY_FINAL_TYPE. + int *array; + size_t length; + }; + + #define DYNARRAY_STRUCT dynarray_int + #define DYNARRAY_ELEMENT int + #define DYNARRAY_PREFIX dynarray_int_ + #define DYNARRAY_FINAL_TYPE struct int_array + #include <malloc/dynarray-skeleton.c> + + To create a three-element array with elements 1, 2, 3, use this + code: + + struct dynarray_int dyn; + dynarray_int_init (&dyn); + for (int i = 1; i <= 3; ++i) + { + int *place = dynarray_int_emplace (&dyn); + assert (place != NULL); + *place = i; + } + struct int_array result; + bool ok = dynarray_int_finalize (&dyn, &result); + assert (ok); + assert (result.length == 3); + assert (result.array[0] == 1); + assert (result.array[1] == 2); + assert (result.array[2] == 3); + free (result.array); + + If the elements contain resources which must be freed, define + DYNARRAY_ELEMENT_FREE appropriately, like this: + + struct str_array + { + char **array; + size_t length; + }; + + #define DYNARRAY_STRUCT dynarray_str + #define DYNARRAY_ELEMENT char * + #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr) + #define DYNARRAY_PREFIX dynarray_str_ + #define DYNARRAY_FINAL_TYPE struct str_array + #include <malloc/dynarray-skeleton.c> + */ + + +/* The implementation is imported from glibc. */ + +/* Avoid possible conflicts with symbols exported by the GNU libc. */ +#define __libc_dynarray_at_failure gl_dynarray_at_failure +#define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge +#define __libc_dynarray_finalize gl_dynarray_finalize +#define __libc_dynarray_resize_clear gl_dynarray_resize_clear +#define __libc_dynarray_resize gl_dynarray_resize + +#if defined DYNARRAY_STRUCT || defined DYNARRAY_ELEMENT || defined DYNARRAY_PREFIX + +# include <libc-config.h> + +/* Define auxiliary structs and declare auxiliary functions, common to all + instantiations of dynarray. */ +# include <malloc/dynarray.h> + +/* Define the instantiation, specified through + DYNARRAY_STRUCT + DYNARRAY_ELEMENT + DYNARRAY_PREFIX + etc. */ +# include <malloc/dynarray-skeleton.c> + +#else + +/* This file is being included from one of the malloc/dynarray_*.c files. */ +# include <malloc/dynarray.h> + +#endif + +#endif /* _GL_DYNARRAY_H */ diff --git a/support/malloc/dynarray_resize.c b/support/malloc/dynarray_resize.c new file mode 100644 index 00000000..5a57166a --- /dev/null +++ b/support/malloc/dynarray_resize.c @@ -0,0 +1,68 @@ +/* Increase the size of a dynamic array. + Copyright (C) 2017-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _LIBC +# include <libc-config.h> +#endif + +#include <dynarray.h> +#include <errno.h> +#include <intprops.h> +#include <stdlib.h> +#include <string.h> + +bool +__libc_dynarray_resize (struct dynarray_header *list, size_t size, + void *scratch, size_t element_size) +{ + /* The existing allocation provides sufficient room. */ + if (size <= list->allocated) + { + list->used = size; + return true; + } + + /* Otherwise, use size as the new allocation size. The caller is + expected to provide the final size of the array, so there is no + over-allocation here. */ + + size_t new_size_bytes; + if (INT_MULTIPLY_WRAPV (size, element_size, &new_size_bytes)) + { + /* Overflow. */ + __set_errno (ENOMEM); + return false; + } + void *new_array; + if (list->array == scratch) + { + /* The previous array was not heap-allocated. */ + new_array = malloc (new_size_bytes); + if (new_array != NULL && list->array != NULL) + memcpy (new_array, list->array, list->used * element_size); + } + else + new_array = realloc (list->array, new_size_bytes); + if (new_array == NULL) + return false; + list->array = new_array; + list->allocated = size; + list->used = size; + return true; +} +libc_hidden_def (__libc_dynarray_resize) |