Make it build and run on MacOS X
authorThorsten lockert <tholo@sigmasoft.com>
Sun, 26 Oct 2003 19:17:28 +0000 (19:17 +0000)
committerThorsten lockert <tholo@sigmasoft.com>
Sun, 26 Oct 2003 19:17:28 +0000 (19:17 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1674 65c4cc65-6c06-0410-ace0-fbb531ad65f3

dlfcn.c [new file with mode: 0755]
poll.c [new file with mode: 0755]

diff --git a/dlfcn.c b/dlfcn.c
new file mode 100755 (executable)
index 0000000..6024496
--- /dev/null
+++ b/dlfcn.c
@@ -0,0 +1,1313 @@
+/*
+Copyright (c) 2002 Jorge Acereda  <jacereda@users.sourceforge.net> &
+                   Peter O'Gorman <ogorman@users.sourceforge.net>
+                   
+Portions may be copyright others, see the AUTHORS file included with this
+distribution.                  
+
+Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
+
+Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <mach-o/dyld.h>
+#include <mach-o/nlist.h>
+#include <mach-o/getsect.h>
+/* Just playing to see if it would compile with the freebsd headers, it does,
+ * but because of the different values for RTLD_LOCAL etc, it would break binary
+ * compat... oh well
+ */
+#ifndef __BSD_VISIBLE
+#define __BSD_VISIBLE 1
+#endif
+#include <asterisk/dlfcn-compat.h>
+
+#ifndef dl_restrict
+#define dl_restrict __restrict
+#endif
+/* This is not available on 10.1 */
+#ifndef LC_LOAD_WEAK_DYLIB
+#define        LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
+#endif
+
+/* With this stuff here, this thing may actually compile/run on 10.0 systems
+ * Not that I have a 10.0 system to test it on anylonger
+ */
+#ifndef LC_REQ_DYLD
+#define LC_REQ_DYLD 0x80000000
+#endif
+#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
+#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
+#endif
+#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
+#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
+#endif
+#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
+#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
+#endif
+#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
+#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
+#endif
+/* These symbols will be looked for in dyld */
+static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
+static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
+static NSSymbol(*dyld_NSLookupSymbolInImage)
+       (const struct mach_header *, const char *, unsigned long) = 0;
+
+/* Define this to make dlcompat reuse data block. This way in theory we save
+ * a little bit of overhead. However we then couldn't correctly catch excess
+ * calls to dlclose(). Hence we don't use this feature
+ */
+#undef REUSE_STATUS
+
+/* Size of the internal error message buffer (used by dlerror()) */
+#define ERR_STR_LEN                    251
+
+/* Maximum number of search paths supported by getSearchPath */
+#define MAX_SEARCH_PATHS       32
+
+
+#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
+#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
+
+/* internal flags */
+#define DL_IN_LIST 0x01
+
+/* our mutex */
+static pthread_mutex_t dlcompat_mutex;
+/* Our thread specific storage
+ */
+static pthread_key_t dlerror_key;
+
+struct dlthread
+{
+       int lockcnt;
+       unsigned char errset;
+       char errstr[ERR_STR_LEN];
+};
+
+/* This is our central data structure. Whenever a module is loaded via
+ * dlopen(), we create such a struct.
+ */
+struct dlstatus
+{
+       struct dlstatus *next;          /* pointer to next element in the linked list */
+       NSModule module;
+       const struct mach_header *lib;
+       int refs;                                       /* reference count */
+       int mode;                                       /* mode in which this module was loaded */
+       dev_t device;
+       ino_t inode;
+       int flags;                                      /* Any internal flags we may need */
+};
+
+/* Head node of the dlstatus list */
+static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
+static struct dlstatus *stqueue = &mainStatus;
+
+
+/* Storage for the last error message (used by dlerror()) */
+/* static char err_str[ERR_STR_LEN]; */
+/* static int err_filled = 0; */
+
+/* Prototypes to internal functions */
+static void debug(const char *fmt, ...);
+static void error(const char *str, ...);
+static const char *safegetenv(const char *s);
+static const char *searchList(void);
+static const char *getSearchPath(int i);
+static const char *getFullPath(int i, const char *file);
+static const struct stat *findFile(const char *file, const char **fullPath);
+static int isValidStatus(struct dlstatus *status);
+static inline int isFlagSet(int mode, int flag);
+static struct dlstatus *lookupStatus(const struct stat *sbuf);
+static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
+static int promoteLocalToGlobal(struct dlstatus *dls);
+static void *reference(struct dlstatus *dls, int mode);
+static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
+static struct dlstatus *allocStatus(void);
+static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
+static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
+static const char *get_lib_name(const struct mach_header *mh);
+static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
+static void dlcompat_init_func(void);
+static inline void dolock(void);
+static inline void dounlock(void);
+static void dlerrorfree(void *data);
+static void resetdlerror(void);
+static const struct mach_header *my_find_image(const char *name);
+static const struct mach_header *image_for_address(const void *address);
+static void dlcompat_cleanup(void);
+static inline const char *dyld_error_str(void);
+
+#if FINK_BUILD
+/* Two Global Functions */
+void *dlsym_prepend_underscore(void *handle, const char *symbol);
+void *dlsym_auto_underscore(void *handle, const char *symbol);
+
+/* And their _intern counterparts */
+static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
+static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
+#endif
+
+/* Functions */
+
+static void debug(const char *fmt, ...)
+{
+#if DEBUG > 1
+       va_list arg;
+       va_start(arg, fmt);
+       fprintf(stderr, "DLDEBUG: ");
+       vfprintf(stderr, fmt, arg);
+       fprintf(stderr, "\n");
+       fflush(stderr);
+       va_end(arg);
+#endif
+}
+
+static void error(const char *str, ...)
+{
+       va_list arg;
+       struct dlthread  *tss;
+       char * err_str;
+       va_start(arg, str);
+       tss = pthread_getspecific(dlerror_key);
+       err_str = tss->errstr;
+       strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
+       vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
+       va_end(arg);
+       debug("ERROR: %s\n", err_str);
+       tss->errset = 1;
+}
+
+static void warning(const char *str)
+{
+#if DEBUG > 0
+       fprintf(stderr, "WARNING: dlcompat: %s\n", str);
+#endif
+}
+
+static const char *safegetenv(const char *s)
+{
+       const char *ss = getenv(s);
+       return ss ? ss : "";
+}
+
+/* because this is only used for debugging and error reporting functions, we
+ * don't really care about how elegant it is... it could use the load
+ * commands to find the install name of the library, but...
+ */
+static const char *get_lib_name(const struct mach_header *mh)
+{
+       unsigned long count = _dyld_image_count();
+       unsigned long i;
+       const char *val = NULL;
+       if (mh)
+       {
+               for (i = 0; i < count; i++)
+               {
+                       if (mh == _dyld_get_image_header(i))
+                       {
+                               val = _dyld_get_image_name(i);
+                               break;
+                       }
+               }
+       }
+       return val;
+}
+
+/* Returns the mach_header for the module bu going through all the loaded images
+ * and finding the one with the same name as the module. There really ought to be
+ * an api for doing this, would be faster, but there isn't one right now
+ */
+static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
+{
+       const char *mod_name = NSNameOfModule(mod);
+       struct mach_header *mh = NULL;
+       unsigned long count = _dyld_image_count();
+       unsigned long i;
+       debug("Module name: %s", mod_name);
+       for (i = 0; i < count; i++)
+       {
+               if (!strcmp(mod_name, _dyld_get_image_name(i)))
+               {
+                       mh = _dyld_get_image_header(i);
+                       break;
+               }
+       }
+       return mh;
+}
+
+
+/* Compute and return a list of all directories that we should search when
+ * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
+ * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
+ * /usr/lib and /lib. Since both of the environments variables can contain a
+ * list of colon seperated paths, we simply concat them and the two other paths
+ * into one big string, which we then can easily parse.
+ * Splitting this string into the actual path list is done by getSearchPath()
+ */
+static const char *searchList()
+{
+       size_t buf_size;
+       static char *buf=NULL;
+       const char *ldlp = safegetenv("LD_LIBRARY_PATH");
+       const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
+       const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
+       if (!stdpath)
+               stdpath = "/usr/local/lib:/lib:/usr/lib";
+       if (!buf)
+       {       
+               buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
+               buf = malloc(buf_size);
+               snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
+                                stdpath, '\0');
+       }
+       return buf;
+}
+
+/* Returns the ith search path from the list as computed by searchList() */
+static const char *getSearchPath(int i)
+{
+       static const char *list = 0;
+       static char **path = (char **)0;
+       static int end = 0;
+       static int numsize = MAX_SEARCH_PATHS;
+       static char **tmp;
+       /* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
+       if (i == -1)
+       {
+               return (const char*)path;
+       }
+       if (!path)
+       {
+               path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
+       }
+       if (!list && !end)
+               list = searchList();
+       if (i >= (numsize))
+       {
+               debug("Increasing size for long PATH");
+               tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
+               if (tmp)
+               {
+                       memcpy(tmp, path, sizeof(char **) * numsize);
+                       free(path);
+                       path = tmp;
+                       numsize += MAX_SEARCH_PATHS;
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+
+       while (!path[i] && !end)
+       {
+               path[i] = strsep((char **)&list, ":");
+
+               if (path[i][0] == 0)
+                       path[i] = 0;
+               end = (list == 0);
+       }
+       return path[i];
+}
+
+static const char *getFullPath(int i, const char *file)
+{
+       static char buf[PATH_MAX];
+       const char *path = getSearchPath(i);
+       if (path)
+       {
+               snprintf(buf, PATH_MAX, "%s/%s", path, file);
+       }
+       return path ? buf : 0;
+}
+
+/* Given a file name, try to determine the full path for that file. Starts
+ * its search in the current directory, and then tries all paths in the 
+ * search list in the order they are specified there.
+ */
+static const struct stat *findFile(const char *file, const char **fullPath)
+{
+       int i = 0;
+       static struct stat sbuf;
+       char *fileName;
+       debug("finding file %s", file);
+       *fullPath = file;
+       if (0 == stat(file, &sbuf))
+               return &sbuf;
+       if (strchr(file, '/'))
+               return 0;                               /* If the path had a / we don't look in env var places */
+       fileName = NULL;
+       if (!fileName)
+               fileName = (char *)file;
+       while ((*fullPath = getFullPath(i++, fileName)))
+       {
+               if (0 == stat(*fullPath, &sbuf))
+                       return &sbuf;
+       }
+       ;
+       return 0;
+}
+
+/* Determine whether a given dlstatus is valid or not */
+static int isValidStatus(struct dlstatus *status)
+{
+       /* Walk the list to verify status is contained in it */
+       struct dlstatus *dls = stqueue;
+       while (dls && status != dls)
+               dls = dls->next;
+       if (dls == 0)
+               error("invalid handle");
+       else if ((dls->module == 0) || (dls->refs == 0))
+               error("handle to closed library");
+       else
+               return TRUE;
+       return FALSE;
+}
+
+static inline int isFlagSet(int mode, int flag)
+{
+       return (mode & flag) == flag;
+}
+
+static struct dlstatus *lookupStatus(const struct stat *sbuf)
+{
+       struct dlstatus *dls = stqueue;
+       debug("looking for status");
+       while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
+                                  || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
+               dls = dls->next;
+       return dls;
+}
+
+static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
+{
+       debug("inserting status");
+       dls->inode = sbuf->st_ino;
+       dls->device = sbuf->st_dev;
+       dls->refs = 0;
+       dls->mode = 0;
+       if ((dls->flags & DL_IN_LIST) == 0)
+       {
+               dls->next = stqueue;
+               stqueue = dls;
+               dls->flags |= DL_IN_LIST;
+       }
+}
+
+static struct dlstatus *allocStatus()
+{
+       struct dlstatus *dls;
+#ifdef REUSE_STATUS
+       dls = stqueue;
+       while (dls && dls->module)
+               dls = dls->next;
+       if (!dls)
+#endif
+               dls = malloc(sizeof(*dls));
+       dls->flags = 0;
+       return dls;
+}
+
+static int promoteLocalToGlobal(struct dlstatus *dls)
+{
+       static int (*p) (NSModule module) = 0;
+       debug("promoting");
+       if (!p)
+               _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
+       return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
+}
+
+static void *reference(struct dlstatus *dls, int mode)
+{
+       if (dls)
+       {
+               if (dls->module == MAGIC_DYLIB_MOD && !isFlagSet(mode, RTLD_GLOBAL))
+               {
+                       warning("trying to open a .dylib with RTLD_LOCAL");
+                       error("unable to open a .dylib with RTLD_LOCAL");
+                       return NULL;
+               }
+               if (isFlagSet(mode, RTLD_GLOBAL) &&
+                       !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
+               {
+                       error("unable to promote local module to global");
+                       return NULL;
+               }
+               dls->mode |= mode;
+               dls->refs++;
+       }
+       else
+               debug("reference called with NULL argument");
+
+       return dls;
+}
+
+static const struct mach_header *my_find_image(const char *name)
+{
+       const struct mach_header *mh = 0;
+       const char *id = NULL;
+       int i = _dyld_image_count();
+       int j;
+       mh = (struct mach_header *)
+               dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
+                                               NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+       if (!mh)
+       {
+               for (j = 0; j < i; j++)
+               {
+                       id = _dyld_get_image_name(j);
+                       if (!strcmp(id, name))
+                       {
+                               mh = _dyld_get_image_header(j);
+                               break;
+                       }
+               }
+       }
+       return mh;
+}
+
+/*
+ * dyld adds libraries by first adding the directly dependant libraries in link order, and
+ * then adding the dependencies for those libraries, so we should do the same... but we don't
+ * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
+ * any of it's direct dependencies, then it probably isn't there.
+ */
+NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
+{
+       int n;
+       struct load_command *lc = 0;
+       struct mach_header *wh;
+       NSSymbol *nssym = 0;
+       if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
+       {
+               lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
+               for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
+               {
+                       if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
+                       {
+                               if ((wh = (struct mach_header *)
+                                        my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
+                                                                                       (char *)lc))))
+                               {
+                                       if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
+                                       {
+                                               nssym = dyld_NSLookupSymbolInImage(wh,
+                                                                                                                  symbol,
+                                                                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
+                                                                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if ((!nssym) && NSIsSymbolNameDefined(symbol))
+               {
+                       /* I've never seen this debug message...*/
+                       debug("Symbol \"%s\" is defined but was not found", symbol);
+               }
+       }
+       return nssym;
+}
+
+/* Up to the caller to free() returned string */
+static inline const char *dyld_error_str()
+{
+       NSLinkEditErrors dylder;
+       int dylderno;
+       const char *dylderrstr;
+       const char *dyldfile;
+       const char* retStr = NULL;
+       NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
+       if (dylderrstr && strlen(dylderrstr))
+       {
+               retStr = malloc(strlen(dylderrstr) +1);
+               strcpy((char*)retStr,dylderrstr);
+       }
+       return retStr;
+}
+
+static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
+{
+       NSSymbol *nssym = 0;
+       void *caller = __builtin_return_address(1);     /* Be *very* careful about inlining */
+       const struct mach_header *caller_mh = 0;
+       const char* savedErrorStr = NULL;
+       resetdlerror();
+#ifndef RTLD_SELF
+#define        RTLD_SELF               ((void *) -3)
+#endif
+       if (NULL == dls)
+               dls = RTLD_SELF;
+       if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
+       {
+               if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
+               {
+                       caller_mh = image_for_address(caller);
+                       if (RTLD_SELF == dls)
+                       {
+                               /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
+                                * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
+                                * this is acceptable.
+                                */
+                               if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
+                               {
+                                       nssym = dyld_NSLookupSymbolInImage(caller_mh,
+                                                                                                          symbol,
+                                                                                                          NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
+                                                                                                          NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+                               }
+                       }
+                       if (!nssym)
+                       {
+                               if (RTLD_SELF == dls)
+                                       savedErrorStr = dyld_error_str();
+                               nssym = search_linked_libs(caller_mh, symbol);
+                       }
+               }
+               else
+               {
+                       if (canSetError)
+                               error("RTLD_SELF and RTLD_NEXT are not supported");
+                       return NULL;
+               }
+       }
+       if (!nssym)
+       {
+
+               if (RTLD_DEFAULT == dls)
+               {
+                       dls = &mainStatus;
+               }
+               if (!isValidStatus(dls))
+                       return NULL;
+
+               if (dls->module != MAGIC_DYLIB_MOD)
+               {
+                       nssym = NSLookupSymbolInModule(dls->module, symbol);
+                       if (!nssym && NSIsSymbolNameDefined(symbol))
+                       {
+                               debug("Searching dependencies");
+                               savedErrorStr = dyld_error_str();
+                               nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
+                       }
+               }
+               else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
+               {
+                       if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
+                       {
+                               nssym = dyld_NSLookupSymbolInImage(dls->lib,
+                                                                                                  symbol,
+                                                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
+                                                                                                  NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+                       }
+                       else if (NSIsSymbolNameDefined(symbol))
+                       {
+                               debug("Searching dependencies");
+                               savedErrorStr = dyld_error_str();
+                               nssym = search_linked_libs(dls->lib, symbol);
+                       }
+               }
+               else if (dls->module == MAGIC_DYLIB_MOD)
+               {
+                       /* Global context, use NSLookupAndBindSymbol */
+                       if (NSIsSymbolNameDefined(symbol))
+                       {
+                               /* There doesn't seem to be a return on error option for this call???
+                                  this is potentially broken, if binding fails, it will improperly
+                                  exit the application. */
+                               nssym = NSLookupAndBindSymbol(symbol);
+                       }
+                       else
+                       {
+                               if (savedErrorStr)
+                                       free((char*)savedErrorStr);                     
+                               savedErrorStr = malloc(256);
+                               snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);      
+                       }
+               }
+       }
+       /* Error reporting */
+       if (!nssym)
+       {
+               if (!savedErrorStr || !strlen(savedErrorStr))
+               {
+                       if (savedErrorStr)
+                               free((char*)savedErrorStr);
+                       savedErrorStr = malloc(256);
+                       snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
+               }
+               if (canSetError)
+               {
+                       error(savedErrorStr);
+               }
+               else
+               {
+                       debug(savedErrorStr);
+               }
+               if (savedErrorStr)
+                       free((char*)savedErrorStr);
+               return NULL;
+       }
+       return NSAddressOfSymbol(nssym);
+}
+
+static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
+{
+       NSObjectFileImage ofi = 0;
+       NSObjectFileImageReturnCode ofirc;
+       struct dlstatus *dls;
+       NSLinkEditErrors ler;
+       int lerno;
+       const char *errstr;
+       const char *file;
+       void (*init) (void);
+       ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
+       switch (ofirc)
+       {
+               case NSObjectFileImageSuccess:
+                       break;
+               case NSObjectFileImageInappropriateFile:
+                       if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
+                       {
+                               if (!isFlagSet(mode, RTLD_GLOBAL))
+                               {
+                                       warning("trying to open a .dylib with RTLD_LOCAL");
+                                       error("unable to open this file with RTLD_LOCAL");
+                                       return NULL;
+                               }
+                       }
+                       else
+                       {
+                               error("opening this file is unsupported on this system");
+                               return NULL;
+                       }
+                       break;
+               case NSObjectFileImageFailure:
+                       error("object file setup failure");
+                       return NULL;
+               case NSObjectFileImageArch:
+                       error("no object for this architecture");
+                       return NULL;
+               case NSObjectFileImageFormat:
+                       error("bad object file format");
+                       return NULL;
+               case NSObjectFileImageAccess:
+                       error("can't read object file");
+                       return NULL;
+               default:
+                       error("unknown error from NSCreateObjectFileImageFromFile()");
+                       return NULL;
+       }
+       dls = lookupStatus(sbuf);
+       if (!dls)
+       {
+               dls = allocStatus();
+       }
+       if (!dls)
+       {
+               error("unable to allocate memory");
+               return NULL;
+       }
+       dls->lib = 0;
+       if (ofirc == NSObjectFileImageInappropriateFile)
+       {
+               if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
+               {
+                       debug("Dynamic lib loaded at %ld", dls->lib);
+                       ofi = MAGIC_DYLIB_OFI;
+                       dls->module = MAGIC_DYLIB_MOD;
+                       ofirc = NSObjectFileImageSuccess;
+                       /* Although it is possible with a bit of work to modify this so it works and
+                          functions with RTLD_NOW, I don't deem it necessary at the moment */
+               }
+               if (!(dls->module))
+               {
+                       NSLinkEditError(&ler, &lerno, &file, &errstr);
+                       if (!errstr || (!strlen(errstr)))
+                               error("Can't open this file type");
+                       else
+                               error(errstr);
+                       if ((dls->flags & DL_IN_LIST) == 0)
+                       {
+                               free(dls);
+                       }
+                       return NULL;
+               }
+       }
+       else
+       {
+               dls->module = NSLinkModule(ofi, path,
+                                                                  NSLINKMODULE_OPTION_RETURN_ON_ERROR |
+                                                                  NSLINKMODULE_OPTION_PRIVATE |
+                                                                  (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
+               NSDestroyObjectFileImage(ofi);
+               if (dls->module)
+               {
+                       dls->lib = get_mach_header_from_NSModule(dls->module);
+               }
+       }
+       if (!dls->module)
+       {
+               NSLinkEditError(&ler, &lerno, &file, &errstr);
+               if ((dls->flags & DL_IN_LIST) == 0)
+               {
+                       free(dls);
+               }
+               error(errstr);
+               return NULL;
+       }
+
+       insertStatus(dls, sbuf);
+       dls = reference(dls, mode);
+       if ((init = dlsymIntern(dls, "__init", 0)))
+       {
+               debug("calling _init()");
+               init();
+       }
+       return dls;
+}
+
+static void dlcompat_init_func(void)
+{
+       static int inited = 0;
+       if (!inited)
+       {
+               inited = 1;
+               _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
+               _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
+                                                 (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
+               _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
+               if (pthread_mutex_init(&dlcompat_mutex, NULL))
+                       exit(1);
+               if (pthread_key_create(&dlerror_key, &dlerrorfree))
+                       exit(1);
+               /* And be neat and tidy and clean up after ourselves */ 
+               atexit(dlcompat_cleanup);
+       }
+}
+
+#if 0
+#pragma CALL_ON_LOAD dlcompat_init_func
+#endif
+
+static void dlcompat_cleanup(void)
+{
+       struct dlstatus *dls;
+       struct dlstatus *next;
+       char *data;
+       data = (char *)searchList();
+       if ( data )
+               free( data );
+       data =  (char *)getSearchPath(-1);
+       if ( data )
+               free( data );
+       pthread_mutex_destroy(&dlcompat_mutex);
+       pthread_key_delete(dlerror_key);
+       next = stqueue;
+       while (next && (next != &mainStatus))
+       {
+               dls = next;
+               next = dls->next;
+               free(dls);
+       }
+}
+
+static void resetdlerror()
+{
+       struct dlthread *tss;
+       tss = pthread_getspecific(dlerror_key);
+       tss->errset = 0;
+}
+
+static void dlerrorfree(void *data)
+{
+       free(data);
+}
+
+/* We kind of want a recursive lock here, but meet a little trouble
+ * because they are not available pre OS X 10.2, so we fake it
+ * using thread specific storage to keep a lock count
+ */ 
+static inline void dolock(void)
+{
+       int err = 0;
+       struct dlthread *tss;
+       tss = pthread_getspecific(dlerror_key);
+       if (!tss)
+       {
+               tss = malloc(sizeof(struct dlthread));
+               tss->lockcnt = 0;
+               tss->errset = 0;
+               if (pthread_setspecific(dlerror_key, tss))
+               {
+                       fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
+                       exit(1);
+               }
+       }
+       if (!tss->lockcnt)
+               err = pthread_mutex_lock(&dlcompat_mutex);
+       tss->lockcnt = tss->lockcnt +1; 
+       if (err)
+               exit(err);
+}
+
+static inline void dounlock(void)
+{
+       int err = 0;
+       struct dlthread *tss;
+       tss = pthread_getspecific(dlerror_key);
+       tss->lockcnt = tss->lockcnt -1;
+       if (!tss->lockcnt)
+               err = pthread_mutex_unlock(&dlcompat_mutex);
+       if (err)
+               exit(err);
+}
+
+void *dlopen(const char *path, int mode)
+{
+       const struct stat *sbuf;
+       struct dlstatus *dls;
+       const char *fullPath;
+       dlcompat_init_func();           /* Just in case */
+       dolock();
+       resetdlerror();
+       if (!path)
+       {
+               dls = &mainStatus;
+               goto dlopenok;
+       }
+       if (!(sbuf = findFile(path, &fullPath)))
+       {
+               error("file \"%s\" not found", path);
+               goto dlopenerror;
+       }
+       /* Now checks that it hasn't been closed already */
+       if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
+       {
+               /* debug("status found"); */
+               dls = reference(dls, mode);
+               goto dlopenok;
+       }
+#ifdef         RTLD_NOLOAD
+       if (isFlagSet(mode, RTLD_NOLOAD))
+       {
+               error("no existing handle and RTLD_NOLOAD specified");
+               goto dlopenerror;
+       }
+#endif
+       if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
+       {
+               error("how can I load something both RTLD_LAZY and RTLD_NOW?");
+               goto dlopenerror;
+       }
+       dls = loadModule(fullPath, sbuf, mode);
+       
+  dlopenok:
+       dounlock();
+       return (void *)dls;
+  dlopenerror:
+       dounlock();
+       return NULL;
+}
+
+#if !FINK_BUILD
+void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
+{
+       int sym_len = strlen(symbol);
+       void *value = NULL;
+       char *malloc_sym = NULL;
+       dolock();
+       malloc_sym = malloc(sym_len + 2);
+       if (malloc_sym)
+       {
+               sprintf(malloc_sym, "_%s", symbol);
+               value = dlsymIntern(handle, malloc_sym, 1);
+               free(malloc_sym);
+       }
+       else
+       {
+               error("Unable to allocate memory");
+               goto dlsymerror;
+       }
+       dounlock();
+       return value;
+  dlsymerror:
+       dounlock();
+       return NULL;
+}
+#endif
+
+#if FINK_BUILD
+
+void *dlsym_prepend_underscore(void *handle, const char *symbol)
+{
+       void *answer;
+       dolock();
+       answer = dlsym_prepend_underscore_intern(handle, symbol);
+       dounlock();
+       return answer;
+}
+
+static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
+{
+/*
+ *     A quick and easy way for porting packages which call dlsym(handle,"sym")
+ *     If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
+ *     this function will be called, and will add the required underscore.
+ *     
+ *     Note that I haven't figured out yet which should be "standard", prepend
+ *     the underscore always, or not at all. These global functions need to go away
+ *     for opendarwin.
+ */
+       int sym_len = strlen(symbol);
+       void *value = NULL;
+       char *malloc_sym = NULL;
+       malloc_sym = malloc(sym_len + 2);
+       if (malloc_sym)
+       {
+               sprintf(malloc_sym, "_%s", symbol);
+               value = dlsymIntern(handle, malloc_sym, 1);
+               free(malloc_sym);
+       }
+       else
+       {
+               error("Unable to allocate memory");
+       }
+       return value;
+}
+
+void *dlsym_auto_underscore(void *handle, const char *symbol)
+{
+       void *answer;
+       dolock();
+       answer = dlsym_auto_underscore_intern(handle, symbol);
+       dounlock();
+       return answer;
+
+}
+static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
+{
+       struct dlstatus *dls = handle;
+       void *addr = 0;
+       addr = dlsymIntern(dls, symbol, 0);
+       if (!addr)
+               addr = dlsym_prepend_underscore_intern(handle, symbol);
+       return addr;
+}
+
+
+void *dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
+{
+       struct dlstatus *dls = handle;
+       void *addr = 0;
+       dolock();
+       addr = dlsymIntern(dls, symbol, 1);
+       dounlock();
+       return addr;
+}
+#endif
+
+int dlclose(void *handle)
+{
+       struct dlstatus *dls = handle;
+       dolock();
+       resetdlerror();
+       if (!isValidStatus(dls))
+       {
+               goto dlcloseerror;
+       }
+       if (dls->module == MAGIC_DYLIB_MOD)
+       {
+               const char *name;
+               if (!dls->lib)
+               {
+                       name = "global context";
+               }
+               else
+               {
+                       name = get_lib_name(dls->lib);
+               }
+               warning("trying to close a .dylib!");
+               error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
+               goto dlcloseerror;
+       }
+       if (!dls->module)
+       {
+               error("module already closed");
+               goto dlcloseerror;
+       }
+       
+       if (dls->refs == 1)
+       {
+               unsigned long options = 0;
+               void (*fini) (void);
+               if ((fini = dlsymIntern(dls, "__fini", 0)))
+               {
+                       debug("calling _fini()");
+                       fini();
+               }
+#ifdef __ppc__
+               options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
+#endif
+#if 1
+/*  Currently, if a module contains c++ static destructors and it is unloaded, we
+ *  get a segfault in atexit(), due to compiler and dynamic loader differences of
+ *  opinion, this works around that.
+ *  I really need a way to figure out from code if this is still necessary.
+ */
+               if ((const struct section *)NULL !=
+                       getsectbynamefromheader(get_mach_header_from_NSModule(dls->module),
+                                                                       "__DATA", "__mod_term_func"))
+               {
+                       options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
+               }
+#endif
+#ifdef RTLD_NODELETE
+               if (isFlagSet(dls->mode, RTLD_NODELETE))
+                       options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
+#endif
+               if (!NSUnLinkModule(dls->module, options))
+               {
+                       error("unable to unlink module");
+                       goto dlcloseerror;
+               }
+               dls->refs--;
+               dls->module = 0;
+               /* Note: the dlstatus struct dls is neither removed from the list
+                * nor is the memory it occupies freed. This shouldn't pose a 
+                * problem in mostly all cases, though.
+                */
+       }
+       dounlock();
+       return 0;
+  dlcloseerror:
+       dounlock();
+       return 1;
+}
+
+const char *dlerror(void)
+{
+       struct dlthread  *tss;
+       char * err_str;
+       tss = pthread_getspecific(dlerror_key);
+       err_str = tss->errstr;
+       tss = pthread_getspecific(dlerror_key);
+       if (tss->errset == 0)
+               return 0;
+       tss->errset = 0;        
+       return (err_str );
+}
+
+/* Given an address, return the mach_header for the image containing it
+ * or zero if the given address is not contained in any loaded images.
+ */
+const struct mach_header *image_for_address(const void *address)
+{
+       unsigned long i;
+       unsigned long j;
+       unsigned long count = _dyld_image_count();
+       struct mach_header *mh = 0;
+       struct load_command *lc = 0;
+       unsigned long addr = NULL;
+       for (i = 0; i < count; i++)
+       {
+               addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
+               mh = _dyld_get_image_header(i);
+               if (mh)
+               {
+                       lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
+                       for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
+                       {
+                               if (LC_SEGMENT == lc->cmd &&
+                                       addr >= ((struct segment_command *)lc)->vmaddr &&
+                                       addr <
+                                       ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
+                               {
+                                       goto image_found;
+                               }
+                       }
+               }
+               mh = 0;
+       }
+  image_found:
+       return mh;
+}
+
+int dladdr(const void * dl_restrict p, Dl_info * dl_restrict info)
+{
+/*
+       FIXME: USe the routine image_for_address.
+*/
+       unsigned long i;
+       unsigned long j;
+       unsigned long count = _dyld_image_count();
+       struct mach_header *mh = 0;
+       struct load_command *lc = 0;
+       unsigned long addr = NULL;
+       unsigned long table_off = (unsigned long)0;
+       int found = 0;
+       if (!info)
+               return 0;
+       dolock();
+       resetdlerror();
+       info->dli_fname = 0;
+       info->dli_fbase = 0;
+       info->dli_sname = 0;
+       info->dli_saddr = 0;
+/* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
+ * to darwin-development AT lists DOT apple DOT com and slightly modified
+ */
+       for (i = 0; i < count; i++)
+       {
+               addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
+               mh = _dyld_get_image_header(i);
+               if (mh)
+               {
+                       lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
+                       for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
+                       {
+                               if (LC_SEGMENT == lc->cmd &&
+                                       addr >= ((struct segment_command *)lc)->vmaddr &&
+                                       addr <
+                                       ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
+                               {
+                                       info->dli_fname = _dyld_get_image_name(i);
+                                       info->dli_fbase = (void *)mh;
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (found)
+                               break;
+               }
+       }
+       if (!found)
+       {
+               dounlock();
+               return 0;
+       }
+       lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
+       for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
+       {
+               if (LC_SEGMENT == lc->cmd)
+               {
+                       if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
+                               break;
+               }
+       }
+       table_off =
+               ((unsigned long)((struct segment_command *)lc)->vmaddr) -
+               ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
+       debug("table off %x", table_off);
+
+       lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
+       for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
+       {
+               if (LC_SYMTAB == lc->cmd)
+               {
+
+                       struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
+                       unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
+                       struct nlist *nearest = NULL;
+                       unsigned long diff = 0xffffffff;
+                       unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
+                       debug("symtable %x", symtable);
+                       for (i = 0; i < numsyms; i++)
+                       {
+                               /* Ignore the following kinds of Symbols */
+                               if ((!symtable->n_value)        /* Undefined */
+                                       || (symtable->n_type >= N_PEXT) /* Debug symbol */
+                                       || (!(symtable->n_type & N_EXT))        /* Local Symbol */
+                                       )
+                               {
+                                       symtable++;
+                                       continue;
+                               }
+                               if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
+                               {
+                                       diff = (unsigned long)symtable->n_value - addr;
+                                       nearest = symtable;
+                               }
+                               symtable++;
+                       }
+                       if (nearest)
+                       {
+                               info->dli_saddr = nearest->n_value + ((void *)p - addr);
+                               info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
+                       }
+               }
+       }
+       dounlock();
+       return 1;
+}
+
+
+/*
+ * Implement the dlfunc() interface, which behaves exactly the same as
+ * dlsym() except that it returns a function pointer instead of a data
+ * pointer.  This can be used by applications to avoid compiler warnings
+ * about undefined behavior, and is intended as prior art for future
+ * POSIX standardization.  This function requires that all pointer types
+ * have the same representation, which is true on all platforms FreeBSD
+ * runs on, but is not guaranteed by the C standard.
+ */
+#if 0 
+dlfunc_t dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
+{
+       union
+       {
+               void *d;
+               dlfunc_t f;
+       } rv;
+       int sym_len = strlen(symbol);
+       char *malloc_sym = NULL;
+       dolock();
+       malloc_sym = malloc(sym_len + 2);
+       if (malloc_sym)
+       {
+               sprintf(malloc_sym, "_%s", symbol);
+               rv.d = dlsymIntern(handle, malloc_sym, 1);
+               free(malloc_sym);
+       }
+       else
+       {
+               error("Unable to allocate memory");
+               goto dlfuncerror;
+       }
+       dounlock();
+       return rv.f;
+  dlfuncerror:
+       dounlock();
+       return NULL;
+}
+#endif
diff --git a/poll.c b/poll.c
new file mode 100755 (executable)
index 0000000..7a9d14e
--- /dev/null
+++ b/poll.c
@@ -0,0 +1,306 @@
+/*---------------------------------------------------------------------------*\
+  $Id$
+
+  NAME
+
+       poll - select(2)-based poll() emulation function for BSD systems.
+
+  SYNOPSIS
+       #include "poll.h"
+
+       struct pollfd
+       {
+           int     fd;
+           short   events;
+           short   revents;
+       }
+
+       int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
+
+  DESCRIPTION
+
+       This file, and the accompanying "poll.h", implement the System V
+       poll(2) system call for BSD systems (which typically do not provide
+       poll()).  Poll() provides a method for multiplexing input and output
+       on multiple open file descriptors; in traditional BSD systems, that
+       capability is provided by select().  While the semantics of select()
+       differ from those of poll(), poll() can be readily emulated in terms
+       of select() -- which is how this function is implemented.
+
+  REFERENCES
+       Stevens, W. Richard. Unix Network Programming.  Prentice-Hall, 1990.
+
+  NOTES
+       1. This software requires an ANSI C compiler.
+
+  LICENSE
+
+       This software is released under the following license:
+
+               Copyright (c) 1995-2002 Brian M. Clapper
+               All rights reserved.
+
+               Redistribution and use in source and binary forms are
+               permitted provided that: (1) source distributions retain
+               this entire copyright notice and comment; (2) modifications
+               made to the software are prominently mentioned, and a copy
+               of the original software (or a pointer to its location) are
+               included; and (3) distributions including binaries display
+               the following acknowledgement: "This product includes
+               software developed by Brian M. Clapper <bmc@clapper.org>"
+               in the documentation or other materials provided with the
+               distribution. The name of the author may not be used to
+               endorse or promote products derived from this software
+               without specific prior written permission.
+
+               THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS
+               OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
+               IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+               PARTICULAR PURPOSE.
+
+       Effectively, this means you can do what you want with the software
+       except remove this notice or take advantage of the author's name.
+       If you modify the software and redistribute your modified version,
+       you must indicate that your version is a modification of the
+       original, and you must provide either a pointer to or a copy of the
+       original.
+\*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*\
+                                Includes
+\*---------------------------------------------------------------------------*/
+
+#include <unistd.h>                         /* standard Unix definitions */
+#include <sys/types.h>                       /* system types */
+#include <sys/time.h>                        /* time definitions */
+#include <assert.h>                          /* assertion macros */
+#include <string.h>                          /* string functions */
+
+#include <asterisk/poll-compat.h>                            /* this package */
+
+/*---------------------------------------------------------------------------*\
+                                 Macros
+\*---------------------------------------------------------------------------*/
+
+#ifndef MAX
+#define MAX(a,b)       ((a) > (b) ? (a) : (b))
+#endif
+
+\f
+/*---------------------------------------------------------------------------*\
+                            Private Functions
+\*---------------------------------------------------------------------------*/
+
+static int map_poll_spec
+#if __STDC__ > 0
+                       (struct pollfd *pArray,
+                         unsigned long  n_fds,
+                         fd_set        *pReadSet,
+                         fd_set        *pWriteSet,
+                         fd_set        *pExceptSet)
+#else
+                        (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
+                         struct pollfd *pArray;
+                         unsigned long  n_fds;
+                         fd_set        *pReadSet;
+                         fd_set        *pWriteSet;
+                         fd_set        *pExceptSet;
+#endif
+{
+    register unsigned long  i;                   /* loop control */
+    register struct        pollfd *pCur;        /* current array element */
+    register int           max_fd = -1;         /* return value */
+
+    /*
+       Map the poll() structures into the file descriptor sets required
+       by select().
+    */
+    for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
+    {
+        /* Skip any bad FDs in the array. */
+
+        if (pCur->fd < 0)
+            continue;
+
+       if (pCur->events & POLLIN)
+       {
+           /* "Input Ready" notification desired. */
+           FD_SET (pCur->fd, pReadSet);
+       }
+
+       if (pCur->events & POLLOUT)
+       {
+           /* "Output Possible" notification desired. */
+           FD_SET (pCur->fd, pWriteSet);
+       }
+
+       if (pCur->events & POLLPRI)
+       {
+           /*
+              "Exception Occurred" notification desired.  (Exceptions
+              include out of band data.
+           */
+           FD_SET (pCur->fd, pExceptSet);
+       }
+
+       max_fd = MAX (max_fd, pCur->fd);
+    }
+
+    return max_fd;
+}
+\f
+static struct timeval *map_timeout
+#if __STDC__ > 0
+                       (int poll_timeout, struct timeval *pSelTimeout)
+#else
+                       (poll_timeout, pSelTimeout)
+                        int             poll_timeout;
+                        struct timeval *pSelTimeout;
+#endif
+{
+    struct timeval *pResult;
+
+    /*
+       Map the poll() timeout value into a select() timeout.  The possible
+       values of the poll() timeout value, and their meanings, are:
+
+       VALUE   MEANING
+
+       -1      wait indefinitely (until signal occurs)
+        0      return immediately, don't block
+       >0      wait specified number of milliseconds
+
+       select() uses a "struct timeval", which specifies the timeout in
+       seconds and microseconds, so the milliseconds value has to be mapped
+       accordingly.
+    */
+
+    assert (pSelTimeout != (struct timeval *) NULL);
+
+    switch (poll_timeout)
+    {
+       case -1:
+           /*
+              A NULL timeout structure tells select() to wait indefinitely.
+           */
+           pResult = (struct timeval *) NULL;
+           break;
+
+       case 0:
+           /*
+              "Return immediately" (test) is specified by all zeros in
+              a timeval structure.
+           */
+           pSelTimeout->tv_sec  = 0;
+           pSelTimeout->tv_usec = 0;
+           pResult = pSelTimeout;
+           break;
+
+       default:
+           /* Wait the specified number of milliseconds. */
+           pSelTimeout->tv_sec  = poll_timeout / 1000; /* get seconds */
+           poll_timeout        %= 1000;                /* remove seconds */
+           pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */
+           pResult = pSelTimeout;
+           break;
+    }
+
+
+    return pResult;
+}
+\f
+static void map_select_results
+#if __STDC__ > 0
+                        (struct pollfd *pArray,
+                         unsigned long  n_fds,
+                         fd_set        *pReadSet,
+                         fd_set        *pWriteSet,
+                         fd_set        *pExceptSet)
+#else
+                        (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
+                         struct pollfd *pArray;
+                         unsigned long  n_fds;
+                         fd_set        *pReadSet;
+                         fd_set        *pWriteSet;
+                         fd_set        *pExceptSet;
+#endif
+{
+    register unsigned long  i;                   /* loop control */
+    register struct        pollfd *pCur;        /* current array element */
+
+    for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
+    {
+        /* Skip any bad FDs in the array. */
+
+        if (pCur->fd < 0)
+            continue;
+
+       /* Exception events take priority over input events. */
+
+       pCur->revents = 0;
+       if (FD_ISSET (pCur->fd, pExceptSet))
+           pCur->revents |= POLLPRI;
+
+       else if (FD_ISSET (pCur->fd, pReadSet))
+           pCur->revents |= POLLIN;
+
+       if (FD_ISSET (pCur->fd, pWriteSet))
+           pCur->revents |= POLLOUT;
+    }
+
+    return;
+}
+\f
+/*---------------------------------------------------------------------------*\
+                            Public Functions
+\*---------------------------------------------------------------------------*/
+
+int poll
+
+#if __STDC__ > 0
+       (struct pollfd *pArray, unsigned long n_fds, int timeout)
+#else
+       (pArray, n_fds, timeout)
+        struct        pollfd *pArray;
+        unsigned long n_fds;
+        int           timeout;
+#endif
+
+{
+    fd_set  read_descs;                          /* input file descs */
+    fd_set  write_descs;                         /* output file descs */
+    fd_set  except_descs;                        /* exception descs */
+    struct  timeval stime;                       /* select() timeout value */
+    int            ready_descriptors;                   /* function result */
+    int            max_fd;                              /* maximum fd value */
+    struct  timeval *pTimeout;                   /* actually passed */
+
+    FD_ZERO (&read_descs);
+    FD_ZERO (&write_descs);
+    FD_ZERO (&except_descs);
+
+    assert (pArray != (struct pollfd *) NULL);
+
+    /* Map the poll() file descriptor list in the select() data structures. */
+
+    max_fd = map_poll_spec (pArray, n_fds,
+                           &read_descs, &write_descs, &except_descs);
+
+    /* Map the poll() timeout value in the select() timeout structure. */
+
+    pTimeout = map_timeout (timeout, &stime);
+
+    /* Make the select() call. */
+
+    ready_descriptors = select (max_fd + 1, &read_descs, &write_descs,
+                               &except_descs, pTimeout);
+
+    if (ready_descriptors >= 0)
+    {
+       map_select_results (pArray, n_fds,
+                           &read_descs, &write_descs, &except_descs);
+    }
+
+    return ready_descriptors;
+}