From bc252d4d26c51cedaf869c24e371d63e69f67f45 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Mon, 12 Jun 2000 17:30:46 +0000 Subject: [PATCH] Added hsearch_r for compatibility needs --- TODO | 1 - configure.in | 3 + include/Makefile.am | 2 +- include/search.h | 177 +++++++++++++++++++++++++++++++ src/Makefile.am | 11 +- src/compat/Makefile.am | 12 +++ src/compat/hsearch_r.c | 236 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 437 insertions(+), 5 deletions(-) create mode 100644 include/search.h create mode 100644 src/compat/Makefile.am create mode 100644 src/compat/hsearch_r.c diff --git a/TODO b/TODO index fcacdbd9..d6a6ac6e 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ M mmap plug and blocking mode problem M plug sync and pos problems M Loopback implementation? -L add hsearch_r code from glibc (for compatibility with older distributions) L move OSS emulation to user space (LD_PRELOAD) diff --git a/configure.in b/configure.in index f2408805..15509aa6 100644 --- a/configure.in +++ b/configure.in @@ -32,6 +32,8 @@ AC_HEADER_TIME dnl Checks for library functions. AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNCS(hsearch_r) +AM_CONDITIONAL(Have_hsearch_r, test x$ac_cv_func_hsearch_r = xyes) ALSA_CHECK_DRIVER SAVE_LIBRARY_VERSION @@ -41,5 +43,6 @@ AC_OUTPUT(Makefile doc/Makefile include/Makefile src/Makefile \ src/control/Makefile src/mixer/Makefile src/pcm/Makefile \ src/pcm/plugin/Makefile src/rawmidi/Makefile src/timer/Makefile \ src/hwdep/Makefile src/seq/Makefile src/instr/Makefile \ + src/compat/Makefile \ test/Makefile utils/Makefile \ utils/alsa-lib.spec) diff --git a/include/Makefile.am b/include/Makefile.am index 2ac68608..e43434c5 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -6,7 +6,7 @@ sysinclude_HEADERS = asoundlib.h header_files=header.h version.h error.h control.h mixer.h pcm.h rawmidi.h \ timer.h hwdep.h seq.h seqmid.h conv.h instr.h footer.h -noinst_HEADERS=$(header_files) +noinst_HEADERS=$(header_files) search.h asoundlib.h: $(header_files) cat $^ > $@ diff --git a/include/search.h b/include/search.h new file mode 100644 index 00000000..0f919b6a --- /dev/null +++ b/include/search.h @@ -0,0 +1,177 @@ +/* Declarations for System V style searching functions. + Copyright (C) 1995-1999, 2000 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _SEARCH_H +#define _SEARCH_H 1 + +#include + +#define __need_size_t +#include + +__BEGIN_DECLS + +#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED +/* Prototype structure for a linked-list data structure. + This is the type used by the `insque' and `remque' functions. */ + +# ifdef __USE_GNU +struct qelem + { + struct qelem *q_forw; + struct qelem *q_back; + char q_data[1]; + }; +# endif + + +/* Insert ELEM into a doubly-linked list, after PREV. */ +extern void insque __P ((void *__elem, void *__prev)); + +/* Unlink ELEM from the doubly-linked list that it is in. */ +extern void remque __P ((void *__elem)); +#endif + + +/* For use with hsearch(3). */ +#ifndef __COMPAR_FN_T +# define __COMPAR_FN_T +typedef int (*__compar_fn_t) __PMT ((__const __ptr_t, __const __ptr_t)); + +# ifdef __USE_GNU +typedef __compar_fn_t comparison_fn_t; +# endif +#endif + +/* Action which shall be performed in the call the hsearch. */ +typedef enum + { + FIND, + ENTER + } +ACTION; + +typedef struct entry + { + char *key; + void *data; + } +ENTRY; + +/* Opaque type for internal use. */ +struct _ENTRY; + +/* Family of hash table handling functions. The functions also + have reentrant counterparts ending with _r. The non-reentrant + functions all work on a signle internal hashing table. */ + +/* Search for entry matching ITEM.key in internal hash table. If + ACTION is `FIND' return found entry or signal error by returning + NULL. If ACTION is `ENTER' replace existing data (if any) with + ITEM.data. */ +extern ENTRY *hsearch __P ((ENTRY __item, ACTION __action)); + +/* Create a new hashing table which will at most contain NEL elements. */ +extern int hcreate __P ((size_t __nel)); + +/* Destroy current internal hashing table. */ +extern void hdestroy __P ((void)); + +#ifdef __USE_GNU +/* Data type for reentrant functions. */ +struct hsearch_data + { + struct _ENTRY *table; + unsigned int size; + unsigned int filled; + }; + +/* Reentrant versions which can handle multiple hashing tables at the + same time. */ +extern int hsearch_r __P ((ENTRY __item, ACTION __action, ENTRY **__retval, + struct hsearch_data *__htab)); +extern int hcreate_r __P ((size_t __nel, struct hsearch_data *__htab)); +extern void hdestroy_r __P ((struct hsearch_data *__htab)); +#endif + + +/* The tsearch routines are very interesting. They make many + assumptions about the compiler. It assumes that the first field + in node must be the "key" field, which points to the datum. + Everything depends on that. */ +/* For tsearch */ +typedef enum +{ + preorder, + postorder, + endorder, + leaf +} +VISIT; + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP and insert a new element if not found. */ +extern void *tsearch __PMT ((__const void *__key, void **__rootp, + __compar_fn_t __compar)); + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP. If no matching entry is available return NULL. */ +extern void *tfind __PMT ((__const void *__key, void *__const *__rootp, + __compar_fn_t __compar)); + +/* Remove the element matching KEY from the tree pointed to by *ROOTP. */ +extern void *tdelete __PMT ((__const void *__key, void **__rootp, + __compar_fn_t __compar)); + +#ifndef __ACTION_FN_T +# define __ACTION_FN_T +typedef void (*__action_fn_t) __PMT ((__const void *__nodep, + VISIT __value, + int __level)); +#endif + +/* Walk through the whole tree and call the ACTION callback for every node + or leaf. */ +extern void twalk __PMT ((__const void *__root, __action_fn_t __action)); + +#ifdef __USE_GNU +/* Callback type for function to free a tree node. If the keys are atomic + data this function should do nothing. */ +typedef void (*__free_fn_t) __PMT ((void *__nodep)); + +/* Destroy the whole tree, call FREEFCT for each node or leaf. */ +extern void tdestroy __PMT ((void *__root, __free_fn_t __freefct)); +#endif + + +/* Perform linear search for KEY by comparing by COMPAR in an array + [BASE,BASE+NMEMB*SIZE). */ +extern void *lfind __PMT ((__const void *__key, __const void *__base, + size_t *__nmemb, size_t __size, + __compar_fn_t __compar)); + +/* Perform linear search for KEY by comparing by COMPAR function in + array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ +extern void *lsearch __PMT ((__const void *__key, void *__base, + size_t *__nmemb, size_t __size, + __compar_fn_t __compar)); + +__END_DECLS + +#endif /* search.h */ diff --git a/src/Makefile.am b/src/Makefile.am index 0d96de4f..b9c1adb8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,11 +1,13 @@ -SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr +SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat COMPATNUM=@LIBTOOL_VERSION_INFO@ lib_LTLIBRARIES = libasound.la libasound_la_SOURCES = error.c libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \ - rawmidi/librawmidi.la timer/libtimer.la hwdep/libhwdep.la \ - seq/libseq.la instr/libinstr.la + rawmidi/librawmidi.la timer/libtimer.la \ + hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \ + compat/libcompat.la + libasound_la_LDFLAGS = -version-info $(COMPATNUM) control/libcontrol.la: @@ -32,4 +34,7 @@ seq/libseq.la: instr/libinstr.la: $(MAKE) -C instr libinstr.la +compat/libcompat.la: + $(MAKE) -C compat libcompat.la + INCLUDES=-I$(top_srcdir)/include diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am new file mode 100644 index 00000000..1ed222b5 --- /dev/null +++ b/src/compat/Makefile.am @@ -0,0 +1,12 @@ +EXTRA_LTLIBRARIES = libcompat.la +EXTRA_libcompat_la_SOURCES = hsearch_r.c + +if Have_hsearch_r +HSEARCH_R = +else +HSEARCH_R = hsearch_r.c +endif + +libcompat_la_SOURCES = $(HSEARCH_R) + +all: libcompat.la diff --git a/src/compat/hsearch_r.c b/src/compat/hsearch_r.c new file mode 100644 index 00000000..b8991914 --- /dev/null +++ b/src/compat/hsearch_r.c @@ -0,0 +1,236 @@ +/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1993. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include + +#define __USE_GNU +#ifndef __set_errno +#define __set_errno(e) errno = (e) +#endif +#include + +/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 + [Knuth] The Art of Computer Programming, part 3 (6.4) */ + + +/* The reentrant version has no static variables to maintain the state. + Instead the interface of all functions is extended to take an argument + which describes the current status. */ +typedef struct _ENTRY +{ + unsigned int used; + ENTRY entry; +} +_ENTRY; + + +/* For the used double hash method the table size has to be a prime. To + correct the user given table size we need a prime test. This trivial + algorithm is adequate because + a) the code is (most probably) called a few times per program run and + b) the number is small because the table must fit in the core */ +static int +isprime (unsigned int number) +{ + /* no even number will be passed */ + unsigned int div = 3; + + while (div * div < number && number % div != 0) + div += 2; + + return number % div != 0; +} + + +/* Before using the hash table we must allocate memory for it. + Test for an existing table are done. We allocate one element + more as the found prime number says. This is done for more effective + indexing as explained in the comment for the hsearch function. + The contents of the table is zeroed, especially the field used + becomes zero. */ +int +hcreate_r (nel, htab) + size_t nel; + struct hsearch_data *htab; +{ + /* Test for correct arguments. */ + if (htab == NULL) + { + __set_errno (EINVAL); + return 0; + } + + /* There is still another table active. Return with error. */ + if (htab->table != NULL) + return 0; + + /* Change nel to the first prime number not smaller as nel. */ + nel |= 1; /* make odd */ + while (!isprime (nel)) + nel += 2; + + htab->size = nel; + htab->filled = 0; + + /* allocate memory and zero out */ + htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY)); + if (htab->table == NULL) + return 0; + + /* everything went alright */ + return 1; +} + + +/* After using the hash table it has to be destroyed. The used memory can + be freed and the local static variable can be marked as not used. */ +void +hdestroy_r (htab) + struct hsearch_data *htab; +{ + /* Test for correct arguments. */ + if (htab == NULL) + { + __set_errno (EINVAL); + return; + } + + if (htab->table != NULL) + /* free used memory */ + free (htab->table); + + /* the sign for an existing table is an value != NULL in htable */ + htab->table = NULL; +} + + +/* This is the search function. It uses double hashing with open addressing. + The argument item.key has to be a pointer to an zero terminated, most + probably strings of chars. The function for generating a number of the + strings is simple but fast. It can be replaced by a more complex function + like ajw (see [Aho,Sethi,Ullman]) if the needs are shown. + + We use an trick to speed up the lookup. The table is created by hcreate + with one more element available. This enables us to use the index zero + special. This index will never be used because we store the first hash + index in the field used where zero means not used. Every other value + means used. The used field can be used as a first fast comparison for + equality of the stored and the parameter value. This helps to prevent + unnecessary expensive calls of strcmp. */ +int +hsearch_r (item, action, retval, htab) + ENTRY item; + ACTION action; + ENTRY **retval; + struct hsearch_data *htab; +{ + unsigned int hval; + unsigned int count; + unsigned int len = strlen (item.key); + unsigned int idx; + + /* Compute an value for the given string. Perhaps use a better method. */ + hval = len; + count = len; + while (count-- > 0) + { + hval <<= 4; + hval += item.key[count]; + } + + /* First hash function: simply take the modul but prevent zero. */ + hval %= htab->size; + if (hval == 0) + ++hval; + + /* The first index tried. */ + idx = hval; + + if (htab->table[idx].used) + { + /* Further action might be required according to the action value. */ + unsigned hval2; + + if (htab->table[idx].used == hval + && strcmp (item.key, htab->table[idx].entry.key) == 0) + { + if (action == ENTER) + htab->table[idx].entry.data = item.data; + + *retval = &htab->table[idx].entry; + return 1; + } + + /* Second hash function, as suggested in [Knuth] */ + hval2 = 1 + hval % (htab->size - 2); + + do + { + /* Because SIZE is prime this guarantees to step through all + available indeces. */ + if (idx <= hval2) + idx = htab->size + idx - hval2; + else + idx -= hval2; + + /* If we visited all entries leave the loop unsuccessfully. */ + if (idx == hval) + break; + + /* If entry is found use it. */ + if (htab->table[idx].used == hval + && strcmp (item.key, htab->table[idx].entry.key) == 0) + { + if (action == ENTER) + htab->table[idx].entry.data = item.data; + + *retval = &htab->table[idx].entry; + return 1; + } + } + while (htab->table[idx].used); + } + + /* An empty bucket has been found. */ + if (action == ENTER) + { + /* If table is full and another entry should be entered return + with error. */ + if (action == ENTER && htab->filled == htab->size) + { + __set_errno (ENOMEM); + *retval = NULL; + return 0; + } + + htab->table[idx].used = hval; + htab->table[idx].entry = item; + + ++htab->filled; + + *retval = &htab->table[idx].entry; + return 1; + } + + __set_errno (ESRCH); + *retval = NULL; + return 0; +} -- 2.47.1