summaryrefslogtreecommitdiffstats
path: root/lib/base
diff options
context:
space:
mode:
Diffstat (limited to 'lib/base')
-rw-r--r--lib/base/Makefile111
-rw-r--r--lib/base/crit.cpp399
-rw-r--r--lib/base/dns.cpp176
-rw-r--r--lib/base/dnsdmain.cpp159
-rw-r--r--lib/base/ereport.cpp249
-rw-r--r--lib/base/eventlog.cpp70
-rw-r--r--lib/base/file.cpp702
-rw-r--r--lib/base/fsmutex.cpp187
-rw-r--r--lib/base/lexer.cpp978
-rw-r--r--lib/base/lexer_pvt.h30
-rw-r--r--lib/base/net.cpp578
-rw-r--r--lib/base/nscperror.c162
-rw-r--r--lib/base/nterrors.cpp83
-rw-r--r--lib/base/plist.cpp1154
-rw-r--r--lib/base/plist_pvt.h122
-rw-r--r--lib/base/pool.cpp654
-rw-r--r--lib/base/rwlock.cpp131
-rw-r--r--lib/base/shexp.cpp290
-rw-r--r--lib/base/shmem.cpp127
-rw-r--r--lib/base/system.cpp264
-rw-r--r--lib/base/systhr.cpp256
-rw-r--r--lib/base/util.cpp1449
22 files changed, 8331 insertions, 0 deletions
diff --git a/lib/base/Makefile b/lib/base/Makefile
new file mode 100644
index 00000000..f58195d3
--- /dev/null
+++ b/lib/base/Makefile
@@ -0,0 +1,111 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# The base library contains the base set of functionality for ldapserver
+# servers. Cross-platform I/O and other generic functions are
+# provided here.
+
+
+MCOM_ROOT=../../..
+MODULE=LibBase
+
+include ../../nsdefs.mk
+
+OBJDEST=$(OBJDIR)/lib/base
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libbase.lib
+ifeq ($(BSCINFO), yes)
+BSCS=$(OBJDIR)/lib/libbase.bsc
+endif
+else
+LIBS=$(OBJDIR)/lib/libbase.a
+endif
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+LOCAL_DEPS = $(NSPR_DEP) $(ADMINUTIL_DEP) $(SECURITY_DEP) $(DBM_DEP)
+
+all: $(LOCAL_DEPS) $(OBJDEST) $(LIBS) $(BSCS)
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+ifeq ($(ARCH), WINNT)
+OSOBJS = nterrors.o eventlog.o eventhandler.o ntpipe.o pathnames.o
+else
+OSOBJS =
+endif
+
+OBJS = $(addprefix $(OBJDEST)/, \
+ dstats.o \
+ daemon.o \
+ shexp.o \
+ regexp.o \
+ pblock.o \
+ plist.o \
+ buffer.o \
+ netbuf.o \
+ file.o \
+ net.o \
+ session.o \
+ cinfo.o \
+ util.o \
+ ereport.o \
+ sem.o \
+ fsmutex.o \
+ systhr.o \
+ crit.o \
+ rwlock.o \
+ dns.o \
+ dnsdmain.o \
+ shmem.o \
+ dll.o \
+ servssl.o \
+ lexer.o \
+ restart.o \
+ objndx.o \
+ cache.o \
+ pool.o \
+ time_cache.o \
+ dns_cache.o \
+ system.o \
+ xp.o \
+ nscperror.o \
+ language.o \
+ fasttime.o \
+ secpwd.o \
+ $(OSOBJS) \
+ )
+
+MODULE_CFLAGS=-I$(NSROOT)/include/base
+
+ifeq ($(PRODUCT),"Netscape Catalog Server")
+ifeq ($(ARCH), WINNT)
+MCC_INCLUDE := $(subst -I$(MCOM_ROOT)/lib/libnet,,$(MCC_INCLUDE))
+endif
+endif
+
+#$(OBJDEST)/fasttime.o : $(OBJDIR)/fasttime.o
+# cp $< $@
+
+$(LIBS): $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+ifeq ($(ARCH), WINNT)
+ifeq ($(BSCINFO), yes)
+$(BSCS): $(OBJS)
+ $(BSCMAKE) $(OBJDEST)/*.sbr
+endif
+endif
+
+include $(INCLUDE_DEPENDS)
+
diff --git a/lib/base/crit.cpp b/lib/base/crit.cpp
new file mode 100644
index 00000000..06f5fba4
--- /dev/null
+++ b/lib/base/crit.cpp
@@ -0,0 +1,399 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * crit.c: Critical section abstraction. Used in threaded servers to protect
+ * areas where two threads can interfere with each other.
+ *
+ * Condvars are condition variables that are used for thread-thread
+ * synchronization.
+ *
+ * Rob McCool
+ */
+
+#include "systems.h"
+
+#include "netsite.h"
+#include "crit.h"
+#include "pool.h"
+#include "ereport.h"
+
+#include "base/dbtbase.h"
+
+#ifdef USE_NSPR
+/*
+#include "prmon.h"
+#include "private/primpl.h"
+*/
+#include "nspr.h"
+
+/* private/primpl.h is gone fromnspr21 19971028 */
+#if 0
+#ifdef XP_WIN32
+#include "private/primpl.h"
+#endif /* XP_WIN32 */
+#endif
+
+#include "prthread.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prinrval.h"
+
+/*
+ * Defined to replace PR_Monitor() with PR_Lock().
+ */
+typedef struct critical {
+ PRLock *lock;
+ PRUint32 count;
+ PRThread *owner;
+} critical_t;
+
+typedef struct condvar {
+ critical_t *lock;
+ PRCondVar *cvar;
+} condvar_t;
+
+#endif
+/* -------------------------- critical sections --------------------------- */
+
+/* Useful for ASSERTs only. Returns non-zero if the current thread is the owner.
+ */
+NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ return (crit->owner == PR_GetCurrentThread());
+#else
+ return 1;
+#endif
+}
+
+NSAPI_PUBLIC CRITICAL crit_init(void)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)PERM_MALLOC(sizeof(critical_t)) ;
+
+ if (crit) {
+ if (!(crit->lock = PR_NewLock())) {
+ PERM_FREE(crit);
+ return NULL;
+ }
+ crit->count = 0;
+ crit->owner = 0;
+ }
+ return (void *) crit;
+#else
+ return NULL;
+#endif
+}
+
+NSAPI_PUBLIC void crit_enter(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+ PRThread *me = PR_GetCurrentThread();
+
+ if ( crit->owner == me) {
+ NS_ASSERT(crit->count > 0);
+ crit->count++;
+ }
+ else {
+ PR_Lock(crit->lock);
+ NS_ASSERT(crit->count == 0);
+ crit->count = 1;
+ crit->owner = me;
+ }
+#endif
+}
+
+NSAPI_PUBLIC void crit_exit(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ if (crit->owner != PR_GetCurrentThread())
+ return;
+
+ if ( --crit->count == 0) {
+ crit->owner = 0;
+ PR_Unlock(crit->lock);
+ }
+ NS_ASSERT(crit->count >= 0);
+#endif
+}
+
+NSAPI_PUBLIC void crit_terminate(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ PR_DestroyLock((PRLock*)crit->lock);
+ PERM_FREE(crit);
+#endif
+}
+
+
+/* ------------------------- condition variables -------------------------- */
+
+
+NSAPI_PUBLIC CONDVAR condvar_init(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ condvar_t *cvar = (condvar_t*)PERM_MALLOC(sizeof(condvar_t)) ;
+
+ if (crit) {
+ cvar->lock = crit;
+ if ((cvar->cvar = PR_NewCondVar((PRLock *)cvar->lock->lock)) == 0) {
+ PERM_FREE(cvar);
+ return NULL;
+ }
+ }
+ return (void *) cvar;
+#endif
+}
+
+NSAPI_PUBLIC void condvar_wait(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ /* Save away recursion count so we can restore it after the wait */
+ int saveCount = cv->lock->count;
+ PRThread *saveOwner = cv->lock->owner;
+
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ cv->lock->count = 0;
+ cv->lock->owner = 0;
+
+ PR_WaitCondVar(cv->cvar, PR_INTERVAL_NO_TIMEOUT);
+
+ cv->lock->count = saveCount;
+ cv->lock->owner = saveOwner;
+#endif
+}
+
+
+NSAPI_PUBLIC void condvar_timed_wait(CONDVAR _cv, long secs)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ /* Save away recursion count so we can restore it after the wait */
+ int saveCount = cv->lock->count;
+ PRThread *saveOwner = cv->lock->owner;
+
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ cv->lock->count = 0;
+ cv->lock->owner = 0;
+
+ PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+ if (secs > 0)
+ timeout = PR_SecondsToInterval(secs);
+ PR_WaitCondVar(cv->cvar, timeout);
+
+ cv->lock->count = saveCount;
+ cv->lock->owner = saveOwner;
+#endif
+}
+
+
+
+NSAPI_PUBLIC void condvar_notify(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ PR_NotifyCondVar(cv->cvar);
+#endif
+}
+
+NSAPI_PUBLIC void condvar_notifyAll(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ PR_NotifyAllCondVar(cv->cvar);
+#endif
+}
+
+NSAPI_PUBLIC void condvar_terminate(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ PR_DestroyCondVar(cv->cvar);
+ PERM_FREE(cv);
+#endif
+}
+
+/* ----------------------- Counting semaphores ---------------------------- */
+/* These are currently not listed in crit.h because they aren't yet used;
+ * although they do work.
+ */
+
+/*
+ * XXXMB - these should be in NSPR.
+ *
+ */
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+#include <synch.h>
+typedef sema_t counting_sem_t;
+#elif defined(IRIX) && defined(HW_THREADS)
+#include <ulocks.h>
+typedef usema_t *counting_sem_t;
+#else
+typedef struct counting_sem_t {
+ CRITICAL lock;
+ CRITICAL cv_lock;
+ CONDVAR cv;
+ int count;
+ int max;
+} counting_sem_t;
+#endif
+
+NSAPI_PUBLIC COUNTING_SEMAPHORE
+cs_init(int initial_count)
+{
+ counting_sem_t *cs = (counting_sem_t *)PERM_MALLOC(sizeof(counting_sem_t));
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( sema_init(cs, initial_count, USYNC_THREAD, NULL) < 0) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csInitFailureS_), system_errmsg());
+ PERM_FREE(cs);
+ return NULL;
+ }
+
+ return (COUNTING_SEMAPHORE)cs;
+#elif defined(IRIX) && defined(HW_THREADS)
+ usptr_t *arena;
+
+ usconfig(CONF_INITSIZE, 64*1024);
+ if ( (arena = usinit("/tmp/cs.locks")) == NULL)
+ return NULL;
+
+ if ( (cs = (counting_sem_t *)usnewsema(arena, 0)) == NULL)
+ return NULL;
+
+ return cs;
+
+#else
+
+ cs->count = initial_count;
+ cs->lock = crit_init();
+ cs->cv_lock = crit_init();
+ cs->cv = condvar_init(cs->cv_lock);
+
+ return (COUNTING_SEMAPHORE)cs;
+#endif
+}
+
+NSAPI_PUBLIC void
+cs_terminate(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( sema_destroy(cs) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csTerminateFailureS_), system_errmsg());
+ }
+ PERM_FREE(cs);
+ return;
+#elif defined(IRIX) && defined(HW_THREADS)
+ /* usfreesema() */
+ return;
+#else
+ condvar_terminate(cs->cv);
+ crit_terminate(cs->cv_lock);
+ crit_terminate(cs->lock);
+ PERM_FREE(cs);
+
+ return;
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_wait(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( (ret = sema_wait(cs)) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csWaitFailureS_), system_errmsg());
+ return -1;
+ }
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ uspsema(cs);
+ return 0;
+#else
+ crit_enter(cs->lock);
+ while ( cs->count == 0 ) {
+ crit_enter(cs->cv_lock);
+ crit_exit(cs->lock);
+ condvar_wait(cs->cv);
+ crit_exit(cs->cv_lock);
+ crit_enter(cs->lock);
+ }
+ ret = --(cs->count);
+ crit_exit(cs->lock);
+
+ return 0;
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_trywait(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ ret = sema_trywait(cs)?-1:0;
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ ret = uscpsema(cs);
+ return (ret == 1)?0:-1;
+#else
+ crit_enter(cs->lock);
+ if (cs->count > 0) {
+ ret = --(cs->count);
+ crit_exit(cs->lock);
+ return 0;
+ }
+ crit_exit(cs->lock);
+ return -1;
+
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_release(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( (ret = sema_post(cs)) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csPostFailureS_), system_errmsg());
+ return -1;
+ }
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ usvsema(cs);
+ return 0;
+#else
+ crit_enter(cs->lock);
+ ret = ++(cs->count);
+ if (cs->count == 1) {
+ crit_enter(cs->cv_lock);
+ condvar_notify(cs->cv);
+ crit_exit(cs->cv_lock);
+ }
+ crit_exit(cs->lock);
+
+ return 0;
+#endif
+}
diff --git a/lib/base/dns.cpp b/lib/base/dns.cpp
new file mode 100644
index 00000000..f9e38886
--- /dev/null
+++ b/lib/base/dns.cpp
@@ -0,0 +1,176 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dns.c: DNS resolution routines
+ *
+ * Rob McCool
+ */
+#define DNS_GUESSING
+
+#include "netsite.h"
+#ifdef XP_UNIX
+#include "systems.h"
+#else /* XP_WIN32 */
+#include "base/systems.h"
+#endif /* XP_WIN32 */
+
+#include "net.h" /* SYS_NETFD, various headers to do DNS */
+
+/* Under NT, these are taken care of by net.h including winsock.h */
+#ifdef XP_UNIX
+#include <arpa/inet.h> /* inet_ntoa */
+#include <netdb.h> /* struct hostent */
+#ifdef NEED_GHN_PROTO
+extern "C" int gethostname (char *name, size_t namelen);
+#endif
+#endif
+#ifdef DNS_CACHE
+#include "base/dns_cache.h"
+#include "base/ereport.h"
+#endif /* DNS_CACHE */
+#include <stdio.h>
+#include <nspr.h>
+#include "frame/conf.h"
+
+/* ---------------------------- dns_find_fqdn ----------------------------- */
+
+
+/* defined in dnsdmain.c */
+extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname);
+
+char *net_find_fqdn(PRHostEnt *p)
+{
+ int x;
+
+ if((!p->h_name) || (!p->h_aliases))
+ return NULL;
+
+ if(!strchr(p->h_name, '.')) {
+ for(x = 0; p->h_aliases[x]; ++x) {
+ if((strchr(p->h_aliases[x], '.')) &&
+ (!strncmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
+ {
+ return STRDUP(p->h_aliases[x]);
+ }
+ }
+#ifdef DNS_GUESSING
+ return dns_guess_domain(p->h_name);
+#else
+ return NULL;
+#endif /* DNS_GUESSING */
+ }
+ else
+ return STRDUP(p->h_name);
+}
+
+
+/* ----------------------------- dns_ip2host ------------------------------ */
+
+
+char *dns_ip2host(char *ip, int verify)
+{
+ /* struct in_addr iaddr; */
+ PRNetAddr iaddr;
+ char *hn;
+#ifdef DNS_CACHE
+ dns_cache_entry_t *dns_entry;
+#endif
+ static unsigned long laddr = 0;
+ static char myhostname[256];
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+
+ err = PR_InitializeNetAddr(PR_IpAddrNull, 0, &iaddr);
+
+ if((iaddr.inet.ip = inet_addr(ip)) == -1)
+ goto bong;
+
+#ifdef DNS_CACHE
+ if ( (dns_entry = dns_cache_lookup_ip((unsigned int)iaddr.inet.ip)) ) {
+ hn = NULL;
+ if ( dns_entry->host &&
+ /* Only use entry if the cache entry has been verified or if
+ * verify is off...
+ */
+ (dns_entry->verified || !verify) ) {
+ hn = STRDUP( dns_entry->host );
+ (void)dns_cache_use_decrement(dns_entry);
+ return hn;
+ }
+ dns_cache_delete(dns_entry);
+ dns_entry = 0;
+ }
+#endif
+
+ /*
+ * See if it happens to be the localhost IP address, and try
+ * the local host name if so.
+ */
+ if (laddr == 0) {
+ laddr = inet_addr("127.0.0.1");
+ myhostname[0] = 0;
+ PR_GetSystemInfo(PR_SI_HOSTNAME, myhostname, sizeof(myhostname));
+ }
+
+ /* Have to match the localhost IP address and have a hostname */
+ if ((iaddr.inet.ip == laddr) && (myhostname[0] != 0)) {
+ /*
+ * Now try for a fully-qualified domain name, starting with
+ * the local hostname.
+ */
+ err = PR_GetHostByName(myhostname,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ /* Don't verify if we get a fully-qualified name this way */
+ verify = 0;
+ }
+ else {
+ err = PR_GetHostByAddr(&iaddr,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+ }
+
+ if ((err == PR_FAILURE) || !(hn = net_find_fqdn(&hent))) goto bong;
+
+
+ if(verify) {
+ char **haddr = 0;
+ err = PR_GetHostByName(hn,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ if(err == PR_SUCCESS) {
+ for(haddr = hent.h_addr_list; *haddr; haddr++) {
+ if(((struct in_addr *)(*haddr))->s_addr == iaddr.inet.ip)
+ break;
+ }
+ }
+
+ if((err == PR_FAILURE) || (!(*haddr)))
+ goto bong;
+ }
+
+#ifdef DNS_CACHE
+ if ( (dns_entry = dns_cache_insert(hn, (unsigned int)iaddr.inet.ip, verify)) ) {
+ (void) dns_cache_use_decrement(dns_entry);
+ }
+#endif /* DNS_CACHE */
+ return hn;
+ bong:
+#ifdef DNS_CACHE
+ /* Insert the lookup failure */
+ if ( (dns_entry = dns_cache_insert(NULL, (unsigned int)iaddr.inet.ip, verify)) ) {
+ (void) dns_cache_use_decrement(dns_entry);
+ }
+#endif /* DNS_CACHE */
+ return NULL;
+}
diff --git a/lib/base/dnsdmain.cpp b/lib/base/dnsdmain.cpp
new file mode 100644
index 00000000..f37e475c
--- /dev/null
+++ b/lib/base/dnsdmain.cpp
@@ -0,0 +1,159 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dnsdmain.c: DNS domain guessing stuff moved out of dns.c because of the
+ * string ball problems
+ */
+
+
+#include "netsite.h"
+#include "base/net.h"
+#include <string.h>
+#include <stdio.h>
+#ifdef XP_UNIX
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include "util.h"
+
+/* Under NT, this is taken care of by net.h including winsock.h */
+#ifdef XP_UNIX
+#include <netdb.h> /* struct hostent */
+#endif
+extern "C" {
+#include <nspr.h>
+}
+#include "frame/conf.h"
+
+
+
+/* This is contained in resolv.h on most systems. */
+#define _PATH_RESCONF "/etc/resolv.conf"
+
+#ifdef XP_UNIX
+NSPR_BEGIN_EXTERN_C
+#ifdef Linux
+extern int getdomainname(char *, size_t);
+#else
+extern int getdomainname(char *, int);
+#endif /* Linux */
+#if defined(HPUX) || defined (UnixWare) || defined(Linux) || defined(IRIX6_5)
+extern int gethostname (char *name, size_t namelen);
+#else
+#ifndef AIX
+extern int gethostname (char *name, int namelen);
+#endif
+#endif
+NSPR_END_EXTERN_C
+#endif
+
+
+/* ---------------------------- dns_guess_domain -------------------------- */
+
+
+extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname)
+{
+ FILE *f;
+ char * cp;
+ int hnlen;
+ char line[256];
+ static int dnlen = 0;
+ static char * domain = 0;
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+ /* Sanity check */
+ if (strchr(hname, '.')) {
+ return STRDUP(hname);
+ }
+
+ if (dnlen == 0) {
+
+ /* First try a little trick that seems to often work... */
+
+ /*
+ * Get the local host name, even it doesn't come back
+ * fully qualified.
+ */
+ line[0] = 0;
+ gethostname(line, sizeof(line));
+ if (line[0] != 0) {
+ /* Is it fully qualified? */
+ domain = strchr(line, '.');
+ if (domain == 0) {
+ /* No, try gethostbyname() */
+ err = PR_GetHostByName(line,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+ if (err == PR_SUCCESS) {
+ /* See if h_name is fully-qualified */
+ if (hent.h_name) domain = strchr(hent.h_name, '.');
+
+ /* Otherwise look for a fully qualified alias */
+ if ((domain == 0) &&
+ (hent.h_aliases && hent.h_aliases[0])) {
+ char **p;
+ for (p = hent.h_aliases; *p; ++p) {
+ domain = strchr(*p, '.');
+ if (domain) break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Still no luck? */
+ if (domain == 0) {
+
+ f = fopen(_PATH_RESCONF, "r");
+
+ /* See if there's a domain entry in their resolver configuration */
+ if(f) {
+ while(fgets(line, sizeof(line), f)) {
+ if(!strncasecmp(line, "domain ", 7)) {
+ for (cp = &line[7]; *cp && isspace(*cp); ++cp) ;
+ if (*cp) {
+ domain = cp;
+ for (; *cp && !isspace(*cp); ++cp) ;
+ *cp = 0;
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+ }
+
+#ifndef NO_DOMAINNAME
+ if (domain == 0) {
+ /* No domain found. Try getdomainname. */
+ getdomainname(line, sizeof(line));
+ if (line[0] != 0) domain = &line[0];
+ }
+#endif
+
+ if (domain != 0) {
+ if (domain[0] == '.') ++domain;
+ domain = STRDUP(domain);
+ dnlen = strlen(domain);
+ }
+ else dnlen = -1;
+ }
+
+ if (domain != 0) {
+ hnlen = strlen(hname);
+ if ((hnlen + dnlen + 2) <= sizeof(line)) {
+ strcpy(line, hname);
+ line[hnlen] = '.';
+ strcpy(&line[hnlen+1], domain);
+ return STRDUP(line);
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/base/ereport.cpp b/lib/base/ereport.cpp
new file mode 100644
index 00000000..3454d01f
--- /dev/null
+++ b/lib/base/ereport.cpp
@@ -0,0 +1,249 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ereport.c: Records transactions, reports errors to administrators, etc.
+ *
+ * Rob McCool
+ */
+
+
+#include "private/pprio.h" /* for nspr20 binary release */
+#include "netsite.h"
+#include "file.h" /* system_fopenWA, system_write_atomic */
+#include "pblock.h"
+#include "session.h"
+#include "util.h" /* util_vsprintf */
+#include "ereport.h"
+
+#include "base/dbtbase.h"
+
+#include <stdarg.h>
+#include <stdio.h> /* vsprintf */
+#include <string.h> /* strcpy */
+#include <time.h> /* localtime */
+
+#ifdef XP_UNIX
+#include <syslog.h> /* error logging to syslog */
+
+static SYS_FILE _error_fd;
+#else /* WIN32 */
+#include <nt/regparms.h>
+#include <nt/messages.h>
+#include "eventlog.h"
+
+static SYS_FILE _error_fd;
+#endif /* XP_UNIX */
+
+static PRBool _ereport_initialized = PR_FALSE;
+
+
+NSAPI_PUBLIC SYS_FILE ereport_getfd(void) { return _error_fd; }
+
+
+
+/* ----------------------------- ereport_init ----------------------------- */
+
+
+NSAPI_PUBLIC char *ereport_init(char *err_fn, char *email,
+ PASSWD pwuser, char *version)
+{
+ char err[MAGNUS_ERROR_LEN];
+ SYS_FILE new_fd;
+
+#ifdef XP_UNIX
+ if(!strcmp(err_fn, "SYSLOG")) {
+#ifdef NET_SSL
+ openlog("secure-httpd", LOG_PID, LOG_DAEMON);
+#else
+ openlog("httpd", LOG_PID, LOG_DAEMON);
+#endif
+ _error_fd = PR_ImportFile(ERRORS_TO_SYSLOG);
+
+ _ereport_initialized = PR_TRUE;
+ return NULL;
+ }
+#endif /* XP_UNIX */
+ if( (new_fd = system_fopenWA(err_fn)) == SYS_ERROR_FD) {
+ util_snprintf(err, MAGNUS_ERROR_LEN, "can't open error log %s (%s)", err_fn,
+ system_errmsg());
+#ifdef XP_UNIX
+ _error_fd = PR_ImportFile(STDERR_FILENO);
+#else
+ _error_fd = PR_ImportFile(NULL);
+#endif
+ return STRDUP(err);
+ }
+ _error_fd = new_fd;
+
+#ifdef XP_UNIX
+ if(pwuser)
+ chown(err_fn, pwuser->pw_uid, pwuser->pw_gid);
+#endif /* XP_UNIX */
+
+ _ereport_initialized = PR_TRUE;
+
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_successfulServerStartup_));
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_SBS_), MAGNUS_VERSION_STRING, BUILD_NUM);
+ if (strcasecmp(BUILD_NUM, version)) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_netscapeExecutableAndSharedLibra_));
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_executableVersionIsS_), version);
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_sharedLibraryVersionIsS_), BUILD_NUM);
+
+ }
+
+ /* Initialize thread-specific error handling */
+ system_errmsg_init();
+
+ return NULL;
+}
+
+
+
+/* -------------------------- ereport_terminate --------------------------- */
+
+
+NSAPI_PUBLIC void ereport_terminate(void)
+{
+ if (!_ereport_initialized)
+ return;
+
+#ifdef XP_UNIX
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_errorReportingShuttingDown_));
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG)
+ system_fclose(_error_fd);
+ else
+ closelog();
+#else /* WIN32 */
+ if(PR_FileDesc2NativeHandle(_error_fd) != NULL)
+ system_fclose(_error_fd);
+#endif /* XP_UNIX */
+
+}
+
+
+/* ------------------------------- ereport -------------------------------- */
+
+
+static int degree_msg[] = {
+ DBT_warning_,
+ DBT_config_,
+ DBT_security_,
+ DBT_failure_,
+ DBT_catastrophe_,
+ DBT_info_,
+ DBT_verbose_
+ };
+
+#ifdef XP_UNIX
+static int degree_syslog[] = {
+ LOG_WARNING, LOG_ERR, LOG_NOTICE, LOG_ALERT, LOG_CRIT, LOG_INFO, LOG_INFO
+};
+#endif/* XP_UNIX */
+
+
+NSAPI_PUBLIC int ereport_v(int degree, char *fmt, va_list args)
+{
+ char errstr[MAX_ERROR_LEN];
+ int pos = 0;
+ struct tm *tms, tmss;
+ time_t t;
+#ifdef MCC_PROXY
+ char *p;
+ int i;
+#endif /* MCC_PROXY */
+
+ if (!_ereport_initialized)
+ return IO_OKAY;
+
+#ifdef XP_UNIX
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG) {
+#endif /* XP_UNIX */
+ t = time(NULL);
+ tms = system_localtime(&t, &tmss);
+ util_strftime(errstr, ERR_TIMEFMT, tms);
+ pos = strlen(errstr);
+
+ pos += util_snprintf(&errstr[pos], MAX_ERROR_LEN - pos, " %s: ",
+ XP_GetAdminStr(degree_msg[degree]));
+#ifdef XP_UNIX
+ }
+#endif /* XP_UNIX */
+
+ pos += util_vsnprintf(&errstr[pos], sizeof(errstr) - pos, fmt, args);
+
+ pos += util_snprintf(&errstr[pos], sizeof(errstr) - pos, ENDLINE);
+
+#ifdef MCC_PROXY
+ /* Thanx to netlib, the proxy sometimes generates multiline err msgs */
+ for(p=errstr, i=pos-1; i>0; i--, p++) {
+ if (*p == '\n' || *p == '\r') *p = ' ';
+ }
+#endif /* MCC_PROXY */
+
+#if defined XP_UNIX
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG)
+ return system_fwrite_atomic(_error_fd, errstr, pos);
+ syslog(degree_syslog[degree], errstr);
+ return IO_OKAY;
+#elif defined XP_WIN32 /* XP_WIN32 */
+ if(PR_FileDesc2NativeHandle(_error_fd) != NULL)
+ {
+#ifdef MCC_HTTPD
+ /* also write to NT Event Log if error is serious */
+ switch (degree)
+ {
+ case LOG_MISCONFIG:
+ case LOG_SECURITY:
+ case LOG_CATASTROPHE:
+ LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ default:
+ break;
+ }
+#endif
+ return system_fwrite_atomic(_error_fd, errstr, pos);
+ }
+ else { /* log to the EventLogger */
+ /* Write to the event logger... */
+ switch (degree) {
+ case LOG_WARN:
+ LogErrorEvent(NULL, EVENTLOG_WARNING_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ case LOG_MISCONFIG:
+ case LOG_SECURITY:
+ case LOG_FAILURE:
+ case LOG_CATASTROPHE:
+ LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+
+ case LOG_INFORM:
+ default:
+ LogErrorEvent(NULL, EVENTLOG_INFORMATION_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ }
+ return (IO_OKAY);
+ }
+#endif /* XP_WIN32 */
+
+}
+
+NSAPI_PUBLIC int ereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ int rv;
+ va_start(args, fmt);
+ rv = ereport_v(degree, fmt, args);
+ va_end(args);
+ return rv;
+}
diff --git a/lib/base/eventlog.cpp b/lib/base/eventlog.cpp
new file mode 100644
index 00000000..b8762842
--- /dev/null
+++ b/lib/base/eventlog.cpp
@@ -0,0 +1,70 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+// //
+// Name: EVENTLOG //
+// Platforms: WIN32 //
+// ...................................................................... //
+// Revision History: //
+// 01-12-95 Initial Version, Aruna Victor (aruna@netscape.com) //
+// 12-02-96 Code cleanup, Andy Hakim (ahakim@netscape.com) //
+// - consolidated admin and http functions into one //
+// - moved registry modification code to installer //
+// - removed several unecessary functions //
+// - changed function parameters to existing functions //
+// //
+//--------------------------------------------------------------------------//
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netsite.h"
+#include "base/eventlog.h"
+#include "frame/conf.h"
+#include <nt/regparms.h>
+#include <nt/messages.h>
+
+HANDLE ghEventSource;
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC HANDLE InitializeLogging(char *szEventLogName)
+{
+ ghEventSource = RegisterEventSource(NULL, szEventLogName);
+ return ghEventSource;
+}
+
+
+
+NSAPI_PUBLIC BOOL TerminateLogging(HANDLE hEventSource)
+{
+ BOOL bReturn = FALSE;
+ if(hEventSource == NULL)
+ hEventSource = ghEventSource;
+ if(hEventSource)
+ bReturn = DeregisterEventSource(hEventSource);
+ return(bReturn);
+}
+
+
+
+NSAPI_PUBLIC BOOL LogErrorEvent(HANDLE hEventSource, WORD fwEventType, WORD fwCategory, DWORD IDEvent, LPTSTR chMsg, LPTSTR lpszMsg)
+{
+ BOOL bReturn = FALSE;
+ LPTSTR lpszStrings[2];
+
+ lpszStrings[0] = chMsg;
+ lpszStrings[1] = lpszMsg;
+
+ if(hEventSource == NULL)
+ hEventSource = ghEventSource;
+
+ if(hEventSource)
+ bReturn = ReportEvent(hEventSource, fwEventType, fwCategory,
+ IDEvent, NULL, 2, 0, (LPCTSTR *)lpszStrings, NULL);
+ return(bReturn);
+}
+
+NSPR_END_EXTERN_C
diff --git a/lib/base/file.cpp b/lib/base/file.cpp
new file mode 100644
index 00000000..7382be46
--- /dev/null
+++ b/lib/base/file.cpp
@@ -0,0 +1,702 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * file.c: system specific functions for reading/writing files
+ *
+ * See file.h for formal definitions of what these functions do
+ *
+ * Rob McCool
+ */
+
+
+#include "base/file.h"
+#include "ereport.h"
+#ifdef BSD_RLIMIT
+#include <sys/time.h>
+#include <sys/resource.h>
+#else
+#include <stdlib.h>
+#include <signal.h>
+#endif
+#ifdef XP_WIN32
+#include <time.h> /* time */
+#include <sys/stat.h> /* stat */
+#include <errno.h>
+#include <direct.h>
+#include <base/nterr.h>
+/* Removed for ns security integration
+#include <xp_error.h>
+*/
+#endif
+#include <prerror.h>
+
+#include "private/pprio.h"
+#include "prlock.h"
+
+extern "C" char *nscperror_lookup(int err);
+
+/* --- globals -------------------------------------------------------------*/
+/* PRFileDesc * SYS_ERROR_FD = NULL; */
+
+const int errbuf_size = 256;
+const unsigned int LOCKFILERANGE=0x7FFFFFFF;
+PRLock *_atomic_write_lock = NULL;
+
+/* --------------------------------- stat --------------------------------- */
+
+
+ /* XXXMB - Can't convert to PR_GetFileInfo because we directly exported
+ * the stat interface... Damn.
+ */
+NSAPI_PUBLIC int system_stat(char *path, struct stat *finfo)
+{
+#ifdef XP_WIN32
+
+ int chop, l;
+
+/* The NT stat is very peculiar about directory names. */
+/* XXX aruna - there is a bug here, maybe in the C runtime.
+ * Stating the same path in a separate program succeeds. From
+ * jblack's profiling, this needs to be replaced by the Win32
+ * calls anyway.*/
+
+ l = strlen(path);
+ if((path[l - 1] == '/') &&
+ (!(isalpha(path[0]) && (!strcmp(&path[1], ":/")))))
+ {
+ chop = 1;
+ path[--l] = '\0';
+ }
+ else chop = 0;
+#endif /* XP_WIN32 */
+
+#ifdef XP_UNIX
+ if(stat(path, finfo) == -1)
+ return -1;
+#else /* XP_WIN32 */
+
+ if(_stat(path, (struct _stat *)finfo) == -1) {
+ /* XXXMB - this sucks;
+ * try to convert to an error code we'll expect...
+ */
+ switch(errno) {
+ case ENOENT: PR_SetError(PR_FILE_NOT_FOUND_ERROR, errno); break;
+ default: PR_SetError(PR_UNKNOWN_ERROR, errno); break;
+ }
+ return -1;
+ }
+
+ /* NT sets the time fields to -1 if it thinks that the file
+ * is a device ( like com1.html, lpt1.html etc) In this case
+ * simply set last modified time to the current time....
+ */
+
+ if (finfo->st_mtime == -1) {
+ finfo->st_mtime = time(NULL);
+ }
+ if (finfo->st_atime == -1) {
+ finfo->st_atime = 0;
+ }
+ if (finfo->st_ctime == -1) {
+ finfo->st_ctime = 0;
+ }
+ if(chop)
+ path[l++] = '/';
+
+#endif /* XP_WIN32 */
+
+ if(S_ISREG(finfo->st_mode) && (path[strlen(path) - 1] == '/')) {
+ /* File with trailing slash */
+ errno = ENOENT;
+ return -1;
+ }
+ return 0;
+}
+
+
+NSAPI_PUBLIC int system_fread(SYS_FILE fd, char *buf, int sz)
+{
+ /* XXXMB - this is the *one* function which does return a length
+ * instead of the IO_ERROR/IO_OKAY.
+ */
+ return PR_Read(fd, buf, sz);
+}
+
+NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, char *buf, int sz) {
+ int n,o,w;
+
+ for(n=sz,o=0; n; n-=w,o+=w) {
+ if((w = PR_Write(fd, &buf[o], n)) < 0)
+ return IO_ERROR;
+ }
+ return IO_OKAY;
+}
+
+/* ---------------------------- Standard UNIX ----------------------------- */
+
+#ifdef XP_UNIX
+
+#include <sys/file.h> /* flock */
+
+NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
+{
+ int ret;
+#if 0
+ if(flock(fd,LOCK_EX) == -1)
+ return IO_ERROR;
+#endif
+ ret = system_fwrite(fd,buf,sz);
+#if 0
+ if(flock(fd,LOCK_UN) == -1)
+ return IO_ERROR; /* ??? */
+#endif
+ return ret;
+}
+
+/* -------------------------- system_nocoredumps -------------------------- */
+
+
+NSAPI_PUBLIC int system_nocoredumps(void)
+{
+#ifdef BSD_RLIMIT
+ struct rlimit rl;
+
+ rl.rlim_cur = 0;
+ rl.rlim_max = 0;
+ return setrlimit(RLIMIT_CORE, &rl);
+#else
+#if defined(SNI)
+/* C++ compiler seems to find more that one overloaded instance of exit() ?! */
+#define EXITFUNC ::exit
+#else
+#define EXITFUNC exit
+#endif
+ signal(SIGQUIT, EXITFUNC);
+ signal(SIGILL, EXITFUNC);
+ signal(SIGTRAP, EXITFUNC);
+ signal(SIGABRT, EXITFUNC);
+ signal(SIGIOT, EXITFUNC);
+ signal(SIGEMT, EXITFUNC);
+ signal(SIGFPE, EXITFUNC);
+ signal(SIGBUS, EXITFUNC);
+ signal(SIGSEGV, EXITFUNC);
+ signal(SIGSYS, EXITFUNC);
+
+
+ return 0;
+#endif
+}
+#endif /* XP_UNIX */
+
+/* --------------------------- file_setinherit ---------------------------- */
+
+NSAPI_PUBLIC int file_setinherit(SYS_FILE fd, int value)
+{
+#if defined(XP_WIN32)
+ int ret;
+
+// ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), 0, value?HANDLE_FLAG_INHERIT:0);
+ // This function did nothing before since the mask was set to 0.
+ ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), HANDLE_FLAG_INHERIT, value?HANDLE_FLAG_INHERIT:0);
+ return ret==0?-1:0;
+#elif defined(XP_UNIX)
+ int flags = 0;
+ PRInt32 nativeFD;
+ PRFileDesc *bottom = fd;
+
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+
+ nativeFD = PR_FileDesc2NativeHandle(bottom);
+#if 0
+fprintf(stderr, "\nInfo(file_setinherit): Native file descriptor is %d\n", nativeFD);
+#endif
+ flags = fcntl(nativeFD, F_GETFD, 0);
+ if(flags == -1)
+ return -1;
+ if(value)
+ flags &= (~FD_CLOEXEC);
+ else
+ flags |= FD_CLOEXEC;
+ fcntl(nativeFD, F_SETFD, flags);
+ return 0;
+
+ /* Comment out for ns security/ nspr integration (HACK for NOW)
+ int flags = fcntl(PR_FileDesc2NativeHandle(fd), F_GETFD, 0);
+ if(flags == -1)
+ return -1;
+ if(value)
+ flags &= (~FD_CLOEXEC);
+ else
+ flags |= FD_CLOEXEC;
+ fcntl(PR_FileDesc2NativeHandle(fd), F_SETFD, flags);
+ return 0;
+ */
+#endif
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenRO(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDONLY, 0);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenWA(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_APPEND, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenRW(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenWT(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC int system_fclose(SYS_FILE fd)
+{
+ return (PR_Close(fd));
+}
+
+
+#ifdef FILE_WIN32
+
+int CgiBuffering;
+
+NSAPI_PUBLIC SYS_FILE system_fopen(char *path, int access, int flags)
+{
+ char p2[MAX_PATH];
+ SYS_FILE ret;
+ HANDLE fd;
+
+ if (strlen(path) >= MAX_PATH) {
+ return SYS_ERROR_FD;
+ }
+
+ file_unix2local(path, p2);
+
+ fd = CreateFile(p2, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, flags, 0, NULL);
+ ret = PR_ImportFile((int32)fd);
+
+ if(ret == INVALID_HANDLE_VALUE)
+ return SYS_ERROR_FD;
+
+ return ret;
+}
+
+
+
+NSAPI_PUBLIC int system_pread(SYS_FILE fd, char *buf, int BytesToRead) {
+ unsigned long BytesRead = 0;
+ int result = 0;
+ BOOLEAN TimeoutSet = FALSE;
+
+ /* XXXMB - nspr20 should be able to do this; but right now it doesn't
+ * return proper error info.
+ * fix it later...
+ */
+ if(ReadFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, BytesToRead, &BytesRead, NULL) == FALSE) {
+ if (GetLastError() == ERROR_BROKEN_PIPE) {
+ return IO_EOF;
+ } else {
+ return IO_ERROR;
+ }
+ }
+ return (BytesRead ? BytesRead : IO_EOF);
+}
+
+NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, char *buf, int BytesToWrite)
+{
+ unsigned long BytesWritten;
+
+ if (WriteFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf,
+ BytesToWrite, &BytesWritten, NULL) == FALSE) {
+ return IO_ERROR;
+ }
+ return BytesWritten;
+}
+
+
+NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
+{
+ int ret;
+
+#if 0
+ if(system_flock(fd) == IO_ERROR)
+ return IO_ERROR;
+#endif
+ /* XXXMB - this is technically thread unsafe, but it catches any
+ * callers of fwrite_atomic when we're single threaded and just coming
+ * to life.
+ */
+ if (!_atomic_write_lock) {
+ _atomic_write_lock = PR_NewLock();
+ }
+ PR_Lock(_atomic_write_lock);
+ ret = system_fwrite(fd,buf,sz);
+ PR_Unlock(_atomic_write_lock);
+#if 0
+ if(system_ulock(fd) == IO_ERROR)
+ return IO_ERROR;
+#endif
+ return ret;
+}
+
+
+NSAPI_PUBLIC void file_unix2local(char *path, char *p2)
+{
+ /* Try to handle UNIX-style paths */
+ if((!strchr(path, FILE_PATHSEP))) {
+ int x;
+
+ for(x = 0; path[x]; x++)
+ p2[x] = (path[x] == '/' ? '\\' : path[x]);
+ p2[x] = '\0';
+ }
+ else
+ strcpy(p2, path);
+}
+
+
+NSAPI_PUBLIC int system_nocoredumps(void)
+{
+ return 0;
+}
+
+/* --------------------------- system_winerr ------------------------------ */
+
+
+#include <winsock.h>
+#include <errno.h>
+#include "util.h"
+
+NSAPI_PUBLIC char *system_winsockerr(void)
+{
+ int errn = WSAGetLastError();
+
+ return FindError(errn);
+}
+
+NSAPI_PUBLIC char *system_winerr(void)
+{
+ int errn = GetLastError();
+
+ if (errn == 0)
+ errn = WSAGetLastError();
+ return FindError(errn);
+}
+
+/* ------------------------- Dir related stuff ---------------------------- */
+
+
+NSAPI_PUBLIC SYS_DIR dir_open(char *pathp)
+{
+ dir_s *ret = (dir_s *) MALLOC(sizeof(dir_s));
+ char path[MAX_PATH];
+ int l;
+
+ if (strlen(pathp) >= MAX_PATH) {
+ return NULL;
+ }
+
+ l = util_sprintf(path, "%s", pathp) - 1;
+ path[strlen(pathp)] = '\0';
+ if(path[strlen(path) - 1] != FILE_PATHSEP)
+ strcpy (path + strlen(path), "\\*.*");
+ else
+ util_sprintf(path, "%s*.*", path);
+
+ ret->de.d_name = NULL;
+ if( (ret->dp = FindFirstFile(path, &ret->fdata)) != INVALID_HANDLE_VALUE)
+ return ret;
+ FREE(ret);
+ return NULL;
+}
+
+NSAPI_PUBLIC SYS_DIRENT *dir_read(SYS_DIR ds)
+{
+ if(FindNextFile(ds->dp, &ds->fdata) == FALSE)
+ return NULL;
+ if(ds->de.d_name)
+ FREE(ds->de.d_name);
+ ds->de.d_name = STRDUP(ds->fdata.cFileName);
+
+ return &ds->de;
+}
+
+NSAPI_PUBLIC void dir_close(SYS_DIR ds)
+{
+ FindClose(ds->dp);
+ if(ds->de.d_name)
+ FREE(ds->de.d_name);
+ FREE(ds);
+}
+
+#endif /* FILE_WIN32 */
+
+NSAPI_PUBLIC int file_notfound(void)
+{
+#ifdef FILE_WIN32
+ int errn = PR_GetError();
+ return (errn == PR_FILE_NOT_FOUND_ERROR);
+#else
+ return (errno == ENOENT);
+#endif
+}
+
+NSAPI_PUBLIC int dir_create_all(char *dir)
+{
+ struct stat fi;
+ char *t;
+
+#ifdef XP_WIN32
+ t = dir + 3;
+#else /* XP_UNIX */
+ t = dir + 1;
+#endif
+ while(1) {
+ t = strchr(t, FILE_PATHSEP);
+ if(t) *t = '\0';
+ if(stat(dir, &fi) == -1) {
+ if(dir_create(dir) == -1)
+ return -1;
+ }
+ if(t) *t++ = FILE_PATHSEP;
+ else break;
+ }
+ return 0;
+}
+
+
+#ifdef XP_UNIX
+#if !defined(SNI) && !defined(LINUX)
+extern char *sys_errlist[];
+#endif /* SNI */
+#endif
+
+#ifdef NET_SSL
+
+#define ERRMSG_SIZE 35
+#ifdef THREAD_ANY
+static int errmsg_key = -1;
+#include "systhr.h"
+/* Removed for ns security integration
+#include "xp_error.h"
+*/
+#else
+static char errmsg[ERRMSG_SIZE];
+#endif
+
+#include "util.h"
+
+static char *_errmsg_new(int code)
+{
+ char *ret;
+#ifdef THREAD_ANY
+ if(!(ret = (char *) systhread_getdata(errmsg_key))) {
+ ret = (char *) PERM_MALLOC(256);
+ systhread_setdata(errmsg_key, (void *)ret);
+ }
+#else
+ ret = errmsg;
+#endif
+ util_snprintf(ret, ERRMSG_SIZE, "libsec code %d", code);
+#ifndef MCC_BATMAN
+ PR_SetError(0,0);
+#endif
+ return ret;
+}
+#endif
+
+
+void system_errmsg_init(void)
+{
+ if (errmsg_key == -1) {
+#if defined(THREAD_ANY) && defined(NET_SSL)
+ errmsg_key = systhread_newkey();
+#endif
+#ifdef XP_WIN32
+ HashNtErrors();
+#endif
+ if (!_atomic_write_lock)
+ _atomic_write_lock = PR_NewLock();
+ }
+}
+
+NSAPI_PUBLIC int system_errmsg_fn(char **buff, size_t maxlen)
+{
+ char static_error[128];
+ char *lmsg = 0; /* Local message pointer */
+ size_t msglen = 0;
+ int sys_error = 0;
+ PRErrorCode nscp_error;
+#ifdef XP_WIN32
+ LPTSTR sysmsg = 0;
+#endif
+
+
+ /* Grab the OS error message */
+#ifdef XP_WIN32
+ sys_error = GetLastError();
+#else
+ sys_error = errno;
+#endif
+ nscp_error = PR_GetError();
+
+ /* If there is a NSPR error, but it is "unknown", try to get the OSError
+ * and use that instead.
+ */
+ if (nscp_error == PR_UNKNOWN_ERROR)
+ errno = PR_GetOSError();
+
+ if (nscp_error != 0 && nscp_error != PR_UNKNOWN_ERROR){
+ char *nscp_error_msg;
+
+ nscp_error_msg = nscperror_lookup(nscp_error);
+ if(nscp_error_msg){
+ PR_SetError(0, 0);
+ lmsg = nscp_error_msg;
+ } else {
+ util_snprintf(static_error, ERRMSG_SIZE, "unknown error %d", nscp_error);
+ lmsg = static_error;
+ }
+ } else {
+#if defined(XP_WIN32)
+ msglen = FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ GetLastError(),
+ LOCALE_SYSTEM_DEFAULT,
+ (LPTSTR)&sysmsg,
+ 0,
+ 0);
+ if (msglen > 0)
+ lmsg = sysmsg;
+ else
+ lmsg = system_winerr();
+ SetLastError(0);
+#else
+/* replaced
+#if defined(SNI) || defined(LINUX)
+ / C++ platform has no definition for sys_errlist /
+ lmsg = strerror(errno);
+#else
+ lmsg = sys_errlist[errno];
+#endif
+with lmsg =strerror(errno);*/
+ lmsg=strerror(errno);
+ errno = 0;
+#endif
+ }
+
+ /* At this point lmsg points to something. */
+ msglen = strlen(lmsg);
+
+ if (*buff == NULL)
+ *buff = STRDUP(lmsg);
+ else if (maxlen > msglen)
+ memcpy(*buff, lmsg, msglen+1);
+ else
+ msglen = 0;
+
+#ifdef XP_WIN32
+ /* NT's FormatMessage() dynamically allocated the msg; free it */
+ if (sysmsg)
+ LocalFree(sysmsg);
+#endif
+
+ return msglen;
+}
+
+NSAPI_PUBLIC char *
+system_errmsg(void)
+{
+ char *buff = 0;
+
+ if (errmsg_key == -1)
+ return "unknown early startup error";
+
+ // rmaxwell - This is extremely lame.
+ // Allocate a buffer in thread local storage to
+ // hold the last error message.
+ // The whole error message facility is broken and should be
+ // updated to get error strings out of the code.
+ if(!(buff = (char *) systhread_getdata(errmsg_key))) {
+ buff = (char *) PERM_MALLOC(errbuf_size);
+ systhread_setdata(errmsg_key, (void *)buff);
+ }
+ system_errmsg_fn(&buff, errbuf_size);
+ if (buff == 0)
+ buff = "Could not retrieve system error message";
+ return buff;
+}
+
+NSAPI_PUBLIC int
+system_rename(char *oldpath, char *newpath)
+{
+ return rename(oldpath, newpath);
+}
+
+NSAPI_PUBLIC int
+system_unlink(char *path)
+{
+ return PR_Delete(path)==PR_FAILURE?-1:0;
+}
+
+NSAPI_PUBLIC int system_lseek(SYS_FILE fd, int off, int wh)
+{
+ switch (wh) {
+ case 0:
+ return PR_Seek(fd, off, PR_SEEK_SET);
+ break;
+ case 1:
+ return PR_Seek(fd, off, PR_SEEK_CUR);
+ break;
+ case 2:
+ return PR_Seek(fd, off, PR_SEEK_END);
+ break;
+ default:
+ return -1;
+ }
+}
+
+NSAPI_PUBLIC int
+system_tlock(SYS_FILE fd)
+{
+ return PR_TLockFile(fd);
+}
+
+NSAPI_PUBLIC int
+system_flock(SYS_FILE fd)
+{
+ return PR_LockFile(fd);
+}
+
+NSAPI_PUBLIC int
+system_ulock(SYS_FILE fd)
+{
+ return PR_UnlockFile(fd);
+}
diff --git a/lib/base/fsmutex.cpp b/lib/base/fsmutex.cpp
new file mode 100644
index 00000000..06fe2403
--- /dev/null
+++ b/lib/base/fsmutex.cpp
@@ -0,0 +1,187 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * fsmutex: Mutexes that are filesystem-based so they're available from more
+ * than one process and address space
+ *
+ * Rob McCool
+ */
+
+#include "base/fsmutex.h"
+#ifdef THREAD_ANY
+#include "base/crit.h"
+#include "base/systhr.h"
+#endif
+
+#include "base/util.h"
+#ifdef XP_WIN32
+typedef HANDLE sys_fsmutex_t;
+#endif
+
+#ifdef XP_UNIX
+#include "base/file.h"
+typedef SYS_FILE sys_fsmutex_t;
+#endif
+
+
+typedef struct {
+ sys_fsmutex_t mutex;
+ char *id;
+#ifdef THREAD_ANY
+ CRITICAL crit;
+#endif
+ int flags;
+} fsmutex_s;
+
+
+
+/* ----------------------------- fsmutex_init ----------------------------- */
+
+
+#ifdef XP_UNIX
+static int
+_fsmutex_create(fsmutex_s *fsm, char *name, int number)
+{
+ char tn[256];
+ SYS_FILE lfd;
+ int visible = (fsm->flags & FSMUTEX_VISIBLE ? 1 : 0);
+
+ util_snprintf(tn, 256, "/tmp/%s.%d", name, number);
+ if(!visible)
+ unlink(tn);
+ if( (lfd = PR_Open(tn, PR_RDWR|PR_CREATE_FILE, 0644)) == NULL)
+ return -1;
+
+ if(!visible)
+ unlink(tn);
+ else
+ fsm->id = PERM_STRDUP(tn);
+ fsm->mutex = lfd;
+ return 0;
+}
+#endif
+
+#ifdef XP_WIN32
+static int
+_fsmutex_create(fsmutex_s *fsm, char *name, int number)
+{
+ char tn[256];
+ util_snprintf(tn, sizeof(tn), "%s.%d", name, number);
+
+ fsm->id = NULL;
+ fsm->mutex = CreateMutex(NULL, FALSE,
+ (fsm->flags & FSMUTEX_VISIBLE ? tn : NULL));
+ return (fsm->mutex ? 0 : -1);
+}
+#endif
+
+NSAPI_PUBLIC FSMUTEX
+fsmutex_init(char *name, int number, int flags)
+{
+ fsmutex_s *ret = (fsmutex_s *) PERM_MALLOC(sizeof(fsmutex_s));
+
+ ret->flags = flags;
+ if(_fsmutex_create(ret, name, number) == -1) {
+ PERM_FREE(ret);
+ return NULL;
+ }
+#ifdef THREAD_ANY
+ if(flags & FSMUTEX_NEEDCRIT)
+ ret->crit = crit_init();
+#endif
+ return (FSMUTEX) ret;
+}
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC void
+fsmutex_setowner(FSMUTEX fsm, uid_t uid, gid_t gid)
+{
+ if(!geteuid())
+ (void) chown( ((fsmutex_s *)fsm)->id, uid, gid);
+}
+#endif
+
+
+/* -------------------------- fsmutex_terminate --------------------------- */
+
+
+#ifdef XP_UNIX
+static void
+_fsmutex_delete(fsmutex_s *fsm)
+{
+ if(fsm->flags & FSMUTEX_VISIBLE)
+ unlink(fsm->id);
+ PERM_FREE(fsm->id);
+ PR_Close(fsm->mutex);
+}
+#endif
+
+#ifdef XP_WIN32
+static void
+_fsmutex_delete(fsmutex_s *fsm)
+{
+ CloseHandle(fsm->mutex);
+}
+#endif
+
+NSAPI_PUBLIC void
+fsmutex_terminate(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+
+ _fsmutex_delete(fsm);
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_terminate(fsm->crit);
+#endif
+ PERM_FREE(fsm);
+}
+
+
+/* ----------------------------- fsmutex_lock ----------------------------- */
+
+
+NSAPI_PUBLIC void
+fsmutex_lock(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_enter(fsm->crit);
+#endif
+#ifdef XP_UNIX
+#ifdef THREAD_NSPR_USER
+ /* Poll to avoid blocking. XXXrobm If errno is wrong this may go awry. */
+ while(system_tlock(fsm->mutex) == -1)
+ systhread_sleep(1000);
+#else
+ system_flock(fsm->mutex );
+#endif
+#endif
+#ifdef XP_WIN32
+ WaitForSingleObject(fsm->mutex, INFINITE);
+#endif
+}
+
+
+/* ---------------------------- fsmutex_unlock ---------------------------- */
+
+
+NSAPI_PUBLIC void
+fsmutex_unlock(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+#ifdef XP_UNIX
+ system_ulock(fsm->mutex);
+#endif
+#ifdef XP_WIN32
+ ReleaseMutex(fsm->mutex);
+#endif
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_exit(fsm->crit);
+#endif
+}
diff --git a/lib/base/lexer.cpp b/lib/base/lexer.cpp
new file mode 100644
index 00000000..e521c51f
--- /dev/null
+++ b/lib/base/lexer.cpp
@@ -0,0 +1,978 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (lexer.c)
+ *
+ * This module provides functions to assist parsers in lexical
+ * analysis. The idea is to provide a slightly higher-level
+ * interface than that of ctype.h.
+ */
+
+#include "netsite.h"
+#include "base/nsassert.h"
+
+#include "lexer_pvt.h"
+#include "base/lexer.h"
+
+/*
+ * Description (lex_class_check)
+ *
+ * This function checks whether a given character belongs to one or
+ * specified character classes.
+ *
+ * Arguments:
+ *
+ * chtab - character class table pointer
+ * code - character code to be tested
+ * cbits - bit mask of character classes
+ *
+ * Returns:
+ *
+ * The return value is zero if the code is not in any of the character
+ * classes. It is non-zero, if the code is in at least one of the
+ * classes.
+ */
+NSAPI_PUBLIC
+int lex_class_check(void * chtab, char code, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ int rv = 0; /* return value */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ bp = lct->lct_bv + code * lct->lct_bvbytes;
+
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & cbits) {
+ rv = 1;
+ break;
+ }
+ cbits >>= 8;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (lex_class_create)
+ *
+ * This function creates a new character class table. A
+ * character class table is used to map a character code to a
+ * set of character classes. The mapping for a given character
+ * is expressed as a bit vector, where each bit indicates the
+ * membership of that character in one of the character classes.
+ *
+ * Arguments:
+ *
+ * classc - the number of character classes being defined
+ * classv - pointers to null-terminated strings containing
+ * the character codes in each character class
+ * pchtab - indicates where to store a returned handle for
+ * the character class table
+ *
+ * Returns:
+ *
+ * If successful, the return value is the number of character
+ * classes specified (classc), and a handle for the created table
+ * is returned through pchtab.
+ *
+ * Usage Notes:
+ *
+ * Null (\000) can never be in any character classes, since it
+ * marks the end of the classv[] strings.
+ *
+ * classv[] can included NULL pointers, in which case bits will be
+ * allocated for corresponding empty character classes.
+ */
+NSAPI_PUBLIC
+int lex_class_create(int classc, char * classv[], void **pchtab)
+{
+ int ncodes = 128; /* number of character encodings */
+ int bvbytes; /* bytes per bit vector */
+ LEXClassTab_t * ct; /* class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* class string pointer */
+ int bitmask; /* class bit mask */
+ int bnum; /* byte number in bit vector */
+ int ci; /* character index */
+ int i; /* class index */
+
+ /* Get number of bytes per bit vector */
+ NS_ASSERT(classc > 0);
+ bvbytes = (classc + 7) >> 3;
+
+ /* Allocate the character class table */
+ ct = (LEXClassTab_t *)calloc(1, sizeof(LEXClassTab_t) + ncodes * bvbytes);
+ if (ct == NULL) {
+
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+
+ /* Initialize the class table */
+ ct->lct_classc = classc;
+ ct->lct_bvbytes = bvbytes;
+ ct->lct_bv = (unsigned char *)(ct + 1);
+
+ /* Initialize the bit vectors */
+ for (i = 0; i < classc; ++i) {
+
+ cp = classv[i];
+ if (cp != NULL) {
+
+ bitmask = 1 << (i & 7);
+ bnum = i >> 7;
+
+ while ((ci = *cp++) != 0) {
+ bp = ct->lct_bv + ci + bnum;
+ *bp |= bitmask;
+ }
+ }
+ }
+
+ /* Return pointer to table */
+ NS_ASSERT(pchtab != NULL);
+ *pchtab = (void *)ct;
+
+ return classc;
+}
+
+NSAPI_PUBLIC
+void lex_class_destroy(void * chtab)
+{
+ FREE((void *)chtab);
+}
+
+NSAPI_PUBLIC
+LEXStream_t * lex_stream_create(LEXStreamGet_t strmget, void * strmid,
+ char * buf, int buflen)
+{
+ LEXStream_t * lst; /* stream structure pointer */
+
+ /* Allocate the stream structure */
+ lst = (LEXStream_t *)MALLOC(sizeof(LEXStream_t));
+ if (lst == NULL) {
+ /* Error - insufficient memory */
+ return 0;
+ }
+
+ lst->lst_strmid = strmid;
+ lst->lst_get = strmget;
+
+ /*
+ * Allocate a buffer for the stream if there's a positive length
+ * but a NULL buffer pointer.
+ */
+ if ((buflen > 0) && (buf == NULL)) {
+
+ buf = (char *)MALLOC(buflen);
+ if (buf == NULL) {
+ FREE((void *)lst);
+ return 0;
+ }
+
+ /* Also initialize the current position and residual length */
+ lst->lst_cp = buf;
+ lst->lst_len = 0;
+ lst->lst_flags = LST_FREEBUF;
+ }
+
+ lst->lst_buf = buf;
+ lst->lst_buflen = buflen;
+
+ return lst;
+}
+
+NSAPI_PUBLIC
+void lex_stream_destroy(LEXStream_t * lst)
+{
+ if ((lst->lst_flags & LST_FREEBUF) && (lst->lst_buf != NULL)) {
+ FREE(lst->lst_buf);
+ }
+ FREE((void *)lst);
+}
+
+/*
+ * Description (lex_token_new)
+ *
+ * This function creates a new token object. A token object is
+ * used to accumulate text in an associated buffer. If the
+ * 'growlen' argument is specified as a value that is greater
+ * than zero, then the token buffer will be reallocated as
+ * necessary to accomodate more text. The initial size of
+ * the token buffer is given by 'initlen', which may be zero,
+ * and should be zero if lex_token_setbuf() is used.
+ *
+ * The token object is allocated from the memory pool given
+ * by the 'pool' argument. The default pool for the current
+ * thread is used if 'pool' is null.
+ *
+ * Arguments:
+ *
+ * pool - handle for memory pool to be used
+ * initlen - initial length of token buffer
+ * growlen - amount to grow a full token buffer
+ * token - pointer to returned token handle
+ *
+ * Returns:
+ *
+ * If successful, the function return value is zero and a handle
+ * for the new token is returned via 'token'. Otherwise a negative
+ * error code is returned.
+ */
+
+NSAPI_PUBLIC
+int lex_token_new(pool_handle_t * pool, int initlen, int growlen, void **token)
+{
+ LEXToken_t * lt; /* new token pointer */
+
+ /* Allocate the token structure */
+ if (pool) {
+ lt = (LEXToken_t *)pool_calloc(pool, 1, sizeof(LEXToken_t));
+ }
+ else {
+ lt = (LEXToken_t *)CALLOC(sizeof(LEXToken_t));
+ }
+ if (lt == NULL) {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+
+ /* Save the memory pool handle for future allocations */
+ lt->lt_mempool = pool;
+
+ /* Allocate the initial token buffer if initlen > 0 */
+ if (initlen > 0) {
+ if (pool) {
+ lt->lt_buf = (char *)pool_malloc(pool, initlen);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(initlen);
+ }
+ if (lt->lt_buf == NULL) {
+ /* Error - insufficient memory */
+ if (pool) {
+ pool_free(pool, (void *)lt);
+ }
+ else {
+ FREE((void *)lt);
+ }
+ return LEXERR_MALLOC;
+ }
+
+ lt->lt_initlen = initlen;
+ lt->lt_buflen = initlen;
+ lt->lt_buf[0] = 0;
+ }
+
+ if (growlen > 0) lt->lt_inclen = growlen;
+
+ NS_ASSERT(token != NULL);
+ *token = (void *)lt;
+
+ return 0;
+}
+
+/*
+ * Description (lex_token_start)
+ *
+ * This function discards any current contents of the token buffer
+ * associated with a specified token object, so that any new data
+ * appended to the token will start at the beginning of the token
+ * buffer. If there is no token buffer currently associated with
+ * the token, and the 'initlen' value specified to lex_token_new()
+ * was greater than zero, then a new token buffer is allocated.
+ * This function enables a token and optionally its token buffer
+ * to be reused.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * If successful, the function return value is zero. Otherwise
+ * a negative error code is returned.
+ */
+
+NSAPI_PUBLIC int
+lex_token_start(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ /* Do we need to allocate a token buffer? */
+ if ((lt->lt_buf == NULL) && (lt->lt_initlen > 0)) {
+
+ /* Allocate the initial token buffer */
+ if (lt->lt_mempool) {
+ lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, lt->lt_initlen);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(lt->lt_initlen);
+ }
+ if (lt->lt_buf == NULL) {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+ lt->lt_buflen = lt->lt_initlen;
+ }
+
+ lt->lt_len = 0;
+ lt->lt_buf[0] = 0;
+
+ return 0;
+}
+
+/*
+ * Description (lex_token_info)
+ *
+ * This function returns information about the token buffer currently
+ * associated with a token object. This includes a pointer to the
+ * token data, if any, the current length of the token data, and the
+ * current size of the token buffer.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * tdatalen - pointer to returned token data length
+ * (may be null)
+ * tbufflen - pointer to returned token buffer length
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the beginning of the
+ * token data, or null if there is no token buffer associated with
+ * the token. The token data length and token buffer length are
+ * returned via 'tdatalen' and 'tbufflen', respectively.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_info(void * token, int * tdatalen, int * tbufflen)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ if (tdatalen) *tdatalen = lt->lt_len;
+ if (tbufflen) *tbufflen = lt->lt_buflen;
+
+ return lt->lt_buf;
+}
+
+/*
+ * Description (lex_token)
+ *
+ * This function returns a pointer to the current token buffer, if any.
+ * If the length of the token is also needed, use lex_token_info().
+ * This function would normally be used when the token is a
+ * null-terminated string. See also lex_token_take().
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * A pointer to the beginning of the current token is returned.
+ * The pointer is null if no token buffer is currently associated
+ * with the token object.
+ */
+
+NSAPI_PUBLIC
+char * lex_token(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ return lt->lt_buf;
+}
+
+/*
+ * Description (lex_token_destroy)
+ *
+ * This function destroys a specified token object. The memory
+ * associated with the token object and its token buffer, if any,
+ * is freed to whence it came. Note that token objects can be
+ * associated with a memory pool, and destroyed implicitly when
+ * the pool is destroyed via pool_destroy().
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ */
+
+NSAPI_PUBLIC
+void lex_token_destroy(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ if (lt) {
+ if (lt->lt_mempool) {
+ if (lt->lt_buf) {
+ pool_free(lt->lt_mempool, (void *)(lt->lt_buf));
+ }
+ pool_free(lt->lt_mempool, (void *)lt);
+ }
+ else {
+ if (lt->lt_buf) {
+ FREE(lt->lt_buf);
+ }
+ FREE(lt);
+ }
+ }
+}
+
+/*
+ * Description (lex_token_get)
+ *
+ * This function returns a pointer to the current token buffer,
+ * leaving the token with no associated token buffer. The caller
+ * assumes ownership of the returned token buffer. The length
+ * of the token data and the length of the token buffer are returned
+ * if requested. Note that lex_token_take() performs a similar
+ * operation.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * tdatalen - pointer to returned token data length
+ * (may be null)
+ * tbufflen - pointer to returned token buffer length
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the beginning of the
+ * token data, or null if there is no token buffer associated with
+ * the token. The token data length and token buffer length are
+ * returned via 'tdatalen' and 'tbufflen', respectively.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_get(void * token, int * tdatalen, int * tbufflen)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ char * tokenstr;
+
+ tokenstr = lt->lt_buf;
+ if (tdatalen) *tdatalen = lt->lt_len;
+ if (tbufflen) *tbufflen = lt->lt_buflen;
+
+ lt->lt_buf = NULL;
+ lt->lt_buflen = 0;
+ lt->lt_len = 0;
+
+ return tokenstr;
+}
+
+/*
+ * Description (lex_token_take)
+ *
+ * This function returns a pointer to the current token buffer,
+ * leaving the token with no associated token buffer. The caller
+ * assumes ownership of the returned token buffer. Note that
+ * lex_token_get() performs a similar operation, but returns more
+ * information.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * A pointer to the beginning of the current token is returned.
+ * The pointer is null if no token buffer is currently associated
+ * with the token object.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_take(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ char * tokenstr;
+
+ tokenstr = lt->lt_buf;
+
+ lt->lt_buf = NULL;
+ lt->lt_buflen = 0;
+ lt->lt_len = 0;
+
+ return tokenstr;
+}
+
+/*
+ * Description (lex_token_append)
+ *
+ * This function appends data to the end of a token. If 'growlen'
+ * was specified as a greater-than-zero value for lex_token_new(),
+ * then the token buffer may be reallocated to accomodate the
+ * new data if necessary. A null byte is maintained in the token
+ * buffer following the token data, but it is not included in the
+ * token data length.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * nbytes - number of bytes of new data
+ * src - pointer to new data
+ *
+ * Returns:
+ *
+ * If successful, the function return value is the new length of
+ * the token data. Otherwise a negative error code is returned.
+ */
+
+NSAPI_PUBLIC
+int lex_token_append(void * token, int nbytes, char * src)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ int bufsize;
+ int length;
+
+ NS_ASSERT(nbytes >= 0);
+ NS_ASSERT((src != NULL) || (nbytes == 0));
+
+ if (nbytes > 0) {
+
+ bufsize = lt->lt_buflen;
+ length = lt->lt_len + nbytes;
+
+ if (length >= bufsize) {
+
+ while (length >= bufsize) {
+ bufsize += lt->lt_inclen;
+ }
+
+ if (lt->lt_mempool) {
+ if (lt->lt_buf) {
+ lt->lt_buf = (char *)pool_realloc(lt->lt_mempool,
+ lt->lt_buf, bufsize);
+ }
+ else {
+ lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, bufsize);
+ }
+ }
+ else {
+ if (lt->lt_buf) {
+ lt->lt_buf = (char *)REALLOC(lt->lt_buf, bufsize);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(bufsize);
+ }
+ }
+ }
+
+ if (lt->lt_buf) {
+
+ memcpy((void *)(lt->lt_buf + lt->lt_len), (void *)src, nbytes);
+ lt->lt_buf[length] = 0;
+ lt->lt_len = length;
+ lt->lt_buflen = bufsize;
+ }
+ else {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+ }
+
+ return lt->lt_len;
+}
+
+NSAPI_PUBLIC
+int lex_next_char(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv; /* return value */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ /* Get the next character from the buffer */
+ rv = *lst->lst_cp;
+
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ /* Update the buffer pointer and length */
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ break;
+ }
+ bitmask >>= 8;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC
+int lex_scan_over(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned char * bp; /* bit vector pointer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int cv = 0; /* current character value */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ cv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + cv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) goto more_token;
+ bitmask >>= 8;
+ }
+
+ done = 1;
+ break;
+
+ more_token:
+ slen += 1;
+ cp += 1;
+ }
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+/*
+ * Description (lex_scan_string)
+ *
+ * This function parses a quoted string into the specified token.
+ * The current character in the LEX stream is taken to be the
+ * beginning quote character. The quote character may be included
+ * in the string by preceding it with a '\'. Any newline
+ * characters to be included in the string must also be preceded
+ * by '\'. The string is terminated by another occurrence of the
+ * quote character, or an unquoted newline, or EOF.
+ *
+ * Arguments:
+ *
+ * lst - pointer to LEX stream structure
+ * token - handle for token
+ * flags - bit flags (unused - must be zero)
+ *
+ * Returns:
+ *
+ * The terminating character is returned, or zero if EOF. The
+ * string is returned in the token, without the beginning and
+ * ending quote characters. An error is indicated by a negative
+ * return value.
+ */
+
+NSAPI_PUBLIC
+int lex_scan_string(LEXStream_t * lst, void * token, int flags)
+{
+ char * cp; /* current pointer in stream buffer */
+ int cv; /* current character value */
+ int rv; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int cquote = 0; /* character quote indication */
+ int qchar = -1; /* quote character */
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+
+ /* Get the next character */
+ cv = *cp;
+
+ /* Pick up the quote character if we don't have it yet */
+ if (qchar < 0) {
+ qchar = cv;
+
+ /* Don't include it in the string */
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ cp += 1;
+ continue;
+ }
+
+ /* cquote is 1 if the last character was '\' */
+ if (cquote == 0) {
+
+ /* Is this a string terminator? */
+ if ((cv == qchar) || (cv == '\n')) {
+
+ /* Append whatever we have to this point */
+ if (slen > 0) goto append_it;
+
+ /*
+ * If the terminator is the expected quote character,
+ * just skip it. If it's anything else, leave it as
+ * the current character.
+ */
+ if (cv == qchar) {
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ }
+
+ done = 1;
+ goto append_it;
+ }
+
+ /* Got the character quote character? */
+ if (cv == '\\') {
+
+ /* Append anything we have so far first */
+ if (slen > 0) goto append_it;
+
+ /* Then skip the character */
+ cquote = 1;
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ cp += 1;
+ continue;
+ }
+ }
+ else {
+
+ /* Include any character following '\' */
+ cquote = 0;
+ }
+
+ /* Include this character in the string */
+ slen += 1;
+ cp += 1;
+ }
+
+ append_it:
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+NSAPI_PUBLIC
+int lex_scan_to(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int cv = 0; /* current character value */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ cv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + cv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ done = 1;
+ goto append_it;
+ }
+ bitmask >>= 8;
+ }
+
+ slen += 1;
+ cp += 1;
+ }
+
+ append_it:
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+NSAPI_PUBLIC
+int lex_skip_over(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ rv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) goto next_ch;
+ bitmask >>= 8;
+ }
+
+ done = 1;
+ break;
+
+ next_ch:
+ slen += 1;
+ cp += 1;
+ }
+
+ if (slen > 0) {
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC
+int lex_skip_to(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ rv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ done = 1;
+ goto update_it;
+ }
+ bitmask >>= 8;
+ }
+ slen += 1;
+ cp += 1;
+ }
+
+ update_it:
+ /* Update the stream buffer pointer and length */
+ if (slen > 0) {
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return rv;
+}
diff --git a/lib/base/lexer_pvt.h b/lib/base/lexer_pvt.h
new file mode 100644
index 00000000..d4a43f38
--- /dev/null
+++ b/lib/base/lexer_pvt.h
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __LEXER_PVT_H
+#define __LEXER_PVT_H
+
+#ifndef _POOL_H_
+#include "base/pool.h"
+#endif /* _POOL_H_ */
+
+typedef struct LEXClassTab_s LEXClassTab_t;
+struct LEXClassTab_s {
+ int lct_classc; /* number of character classes */
+ int lct_bvbytes; /* number of bytes per bit vector */
+ unsigned char * lct_bv; /* pointer to bit vector area */
+};
+
+typedef struct LEXToken_s LEXToken_t;
+struct LEXToken_s {
+ char * lt_buf; /* token buffer pointer */
+ int lt_len; /* length of token data */
+ int lt_buflen; /* current length of buffer */
+ int lt_inclen; /* buffer length increment */
+ int lt_initlen; /* initial length of token buffer */
+ pool_handle_t * lt_mempool; /* token memory pool */
+};
+
+#endif /* __LEXER_PVT_H */
diff --git a/lib/base/net.cpp b/lib/base/net.cpp
new file mode 100644
index 00000000..0d15b121
--- /dev/null
+++ b/lib/base/net.cpp
@@ -0,0 +1,578 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * net.c: sockets abstraction and DNS related things
+ *
+ * Note: sockets created with net_socket are placed in non-blocking mode,
+ * however this API simulates that the calls are blocking.
+ *
+ * Rob McCool
+ */
+
+
+#include "netsite.h"
+#include "prio.h"
+#include "private/pprio.h"
+#include <nspr.h>
+
+#include <frame/conf.h>
+/* Removed for ns security integration
+#include "sslio/sslio.h"
+*/
+
+#include "net.h"
+#include "util.h"
+#include "daemon.h" /* child_exit */
+#include "ereport.h" /* error reporting */
+#include <string.h>
+#ifdef XP_UNIX
+#include <arpa/inet.h> /* inet_ntoa */
+#include <netdb.h> /* hostent stuff */
+#ifdef NEED_GHN_PROTO
+extern "C" int gethostname (char *name, size_t namelen);
+#endif
+#endif /* XP_UNIX */
+#ifdef LINUX
+#include <sys/ioctl.h> /* ioctl */
+#endif
+
+extern "C" {
+#include "ssl.h"
+}
+
+#if defined(OSF1)
+#include <stropts.h>
+#endif
+#include "base/systems.h"
+#include "base/dbtbase.h"
+
+#if defined(OSF1)
+#include <stropts.h>
+#endif
+
+#ifdef IRIX
+#include <bstring.h> /* fd_zero uses bzero */
+#endif
+#include "netio.h"
+
+net_io_t net_io_functions;
+/* removed for ns security integration
+#include "xp_error.h"
+*/
+
+#include "libadmin/libadmin.h"
+
+int net_enabledns = 1;
+int net_enableAsyncDNS = 0;
+int net_listenqsize = DAEMON_LISTEN_SIZE;
+unsigned int NET_BUFFERSIZE = NET_DEFAULT_BUFFERSIZE;
+unsigned int NET_READ_TIMEOUT = NET_DEFAULT_READ_TIMEOUT;
+unsigned int NET_WRITE_TIMEOUT = NET_DEFAULT_WRITE_TIMEOUT;
+unsigned int SSL_HANDSHAKE_TIMEOUT = SSL_DEFAULT_HANDSHAKE_TIMEOUT;
+
+
+/* ------------------------------ net_init -------------------------------- */
+NSAPI_PUBLIC int net_init(int security_on)
+{
+ return 0;
+}
+
+/* ------------------------------ net_socket ------------------------------ */
+NSAPI_PUBLIC SYS_NETFD net_socket(int domain, int type, int protocol)
+{
+ SYS_NETFD sock;
+ SYS_NETFD prsock;
+
+ if (security_active) {
+ if (protocol == IPPROTO_TCP)
+ prsock = PR_NewTCPSocket();
+ else
+ prsock = PR_NewUDPSocket();
+ if(prsock)
+ sock = SSL_ImportFD(NULL, prsock);
+ else sock = NULL;
+ }
+ else {
+ if (protocol == IPPROTO_TCP) sock = PR_NewTCPSocket();
+ else sock = PR_NewUDPSocket();
+ }
+
+ if (sock == NULL)
+ return (SYS_NETFD)SYS_NET_ERRORFD;
+ return sock;
+}
+
+
+/* ---------------------------- net_getsockopt ---------------------------- */
+NSAPI_PUBLIC int net_getsockopt(SYS_NETFD s, int level, int optname,
+ void *optval, int *optlen)
+{
+ return getsockopt(PR_FileDesc2NativeHandle(s), level, optname,
+ (char *)optval, (TCPLEN_T *)optlen);
+}
+
+
+/* ---------------------------- net_setsockopt ---------------------------- */
+
+
+NSAPI_PUBLIC int net_setsockopt(SYS_NETFD s, int level, int optname,
+ const void *optval, int optlen)
+{
+ return setsockopt(PR_FileDesc2NativeHandle(s), level, optname,
+ (const char *)optval, optlen);
+}
+/* ------------------------------ net_listen ------------------------------ */
+
+
+NSAPI_PUBLIC int net_listen(SYS_NETFD s, int backlog)
+{
+ return PR_Listen(s, backlog)==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------- net_create_listener -------------------------- */
+
+
+NSAPI_PUBLIC SYS_NETFD net_create_listener(char *ipstr, int port)
+{
+ SYS_NETFD sd;
+ /*
+ struct sockaddr_in sa_server;
+ */
+ PRNetAddr sa_server;
+ PRStatus status;
+ PRInt32 flags;
+
+ if ((sd = net_socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == SYS_NET_ERRORFD) {
+ return SYS_NET_ERRORFD;
+ }
+
+#ifdef SOLARIS
+ /*
+ * unset NONBLOCK flag;
+ */
+ /* Have no idea why Solaris want to unset NONBLOCK flag when it should
+ be in NON-BLOCK mode, and new NSPR20 does not give file descriptor
+ back, so the code are removed --- yjh
+ flags = fcntl(sd->osfd, F_GETFL, 0);
+ fcntl(sd->osfd, F_SETFL, flags & ~O_NONBLOCK);
+ */
+#endif
+ /* Convert to NSPR21 for ns security integration
+ ZERO((char *) &sa_server, sizeof(sa_server));
+ sa_server.sin_family=AF_INET;
+ sa_server.sin_addr.s_addr = (ipstr ? inet_addr(ipstr) : htonl(INADDR_ANY));
+ sa_server.sin_port=htons(port);
+ if(net_bind(sd, (struct sockaddr *) &sa_server,sizeof(sa_server)) < 0) {
+ return SYS_NET_ERRORFD;
+ }
+ net_listen(sd, net_listenqsize);
+ */
+
+ if (ipstr) {
+ status = PR_InitializeNetAddr(PR_IpAddrNull, port, &sa_server);
+ if (status == PR_SUCCESS) sa_server.inet.ip = inet_addr(ipstr);
+ else return SYS_NET_ERRORFD;
+ }
+ else {
+ status = PR_InitializeNetAddr(PR_IpAddrAny, port, &sa_server);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+ }
+
+ status = PR_Bind(sd, &sa_server);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+
+
+ status = PR_Listen(sd, net_listenqsize);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+
+ return sd;
+}
+/* ------------------------------ net_select ------------------------------ */
+
+/*
+NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e,
+ struct timeval *timeout)
+{
+ PR_fd_set rd, wr, ex;
+ int index;
+ int rv;
+
+ if (nfds > (64*1024))
+ return -1;
+
+ PR_FD_ZERO(&rd);
+ PR_FD_ZERO(&wr);
+ PR_FD_ZERO(&ex);
+
+ for (index=0; index<nfds; index++) {
+ if (FD_ISSET(index, r))
+ PR_FD_NSET(index, &rd);
+ if (FD_ISSET(index, w))
+ PR_FD_NSET(index, &wr);
+ if (FD_ISSET(index, e))
+ PR_FD_NSET(index, &ex);
+ }
+
+ rv = PR_Select(0, &rd, &wr, &ex, PR_SecondsToInterval(timeout->tv_sec));
+ if (rv > 0) {
+ FD_ZERO(r);
+ FD_ZERO(w);
+ FD_ZERO(e);
+ for (index=0; index<nfds; index++) {
+ if (PR_FD_NISSET(index, &rd))
+ FD_SET(index, r);
+ if (PR_FD_NISSET(index, &wr))
+ FD_SET(index, w);
+ if (PR_FD_NISSET(index, &ex))
+ FD_SET(index, e);
+ }
+ }
+
+ return rv;
+}
+*/
+
+NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e,
+ struct timeval *timeout)
+{
+ return 1;
+}
+
+
+/* ----------------------------- net_isalive ------------------------------ */
+
+
+/*
+ * XXXmikep As suggested by shaver@ingenia.com. If everyone was POSIX
+ * compilent, a write() of 0 bytes would work as well
+ */
+NSAPI_PUBLIC int net_isalive(SYS_NETFD sd)
+{
+ char c;
+ if (PR_RecvFrom(sd, &c, 1, MSG_PEEK, NULL, 0) == -1 ) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/* ------------------------------ net_connect ------------------------------ */
+
+NSAPI_PUBLIC int net_connect(SYS_NETFD s, const void *sockaddr, int namelen)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Connect(s, (PRNetAddr *)sockaddr, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+
+ return rv==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------------ net_ioctl ------------------------------ */
+
+
+NSAPI_PUBLIC int net_ioctl(SYS_NETFD s, int tag, void *result)
+{
+#if defined(NET_WINSOCK)
+ return ioctlsocket(PR_FileDesc2NativeHandle(s),tag,(unsigned long *)result);
+#elif defined(XP_UNIX)
+ return ioctl(PR_FileDesc2NativeHandle(s), tag, result);
+#else
+ write me;
+#endif
+
+}
+/* --------------------------- net_getpeername ---------------------------- */
+
+
+NSAPI_PUBLIC int net_getpeername(SYS_NETFD s, struct sockaddr *name,
+ int *namelen)
+{
+#if defined (SNI) || defined (UnixWare)
+ return getpeername(PR_FileDesc2NativeHandle(s), name, (size_t *)namelen);
+#else /* defined (SNI) || defined (UnixWare) */
+ return getpeername(PR_FileDesc2NativeHandle(s), name, (TCPLEN_T *)namelen);
+#endif /* defined (SNI) || defined (UnixWare) */
+}
+
+
+/* ------------------------------ net_close ------------------------------- */
+
+
+NSAPI_PUBLIC int net_close(SYS_NETFD s)
+{
+ return PR_Close(s)==PR_FAILURE?IO_ERROR:0;
+}
+
+NSAPI_PUBLIC int net_shutdown(SYS_NETFD s, int how)
+{
+ switch (how) {
+ case 0:
+ return PR_Shutdown(s, PR_SHUTDOWN_RCV);
+ break;
+ case 1:
+ return PR_Shutdown(s, PR_SHUTDOWN_SEND);
+ break;
+ case 2:
+ return PR_Shutdown(s, PR_SHUTDOWN_BOTH);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* ------------------------------- net_bind ------------------------------- */
+
+NSAPI_PUBLIC int net_bind(SYS_NETFD s, const struct sockaddr *name,
+ int namelen)
+{
+ return PR_Bind(s, (const PRNetAddr *)name)==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------------ net_accept ------------------------------ */
+
+
+NSAPI_PUBLIC SYS_NETFD net_accept(SYS_NETFD sd, struct sockaddr *addr,
+ int *addrlen)
+{
+ SYS_NETFD sock = PR_Accept(sd, (PRNetAddr *)addr, PR_INTERVAL_NO_TIMEOUT);
+
+ if (sock == NULL)
+ return SYS_NET_ERRORFD;
+ return sock;
+}
+
+/* ------------------------------- net_read ------------------------------- */
+
+NSAPI_PUBLIC int net_read(SYS_NETFD fd, char *buf, int sz, int timeout)
+{
+ int rv;
+
+ if (timeout == NET_ZERO_TIMEOUT)
+ timeout = PR_INTERVAL_NO_WAIT;
+ else if (timeout == NET_INFINITE_TIMEOUT)
+ timeout = PR_INTERVAL_NO_TIMEOUT;
+ else
+ timeout = PR_SecondsToInterval(timeout);
+
+ child_status(CHILD_READING);
+ rv = PR_Recv(fd, buf, sz, 0, timeout);
+
+ child_status(CHILD_PROCESSING);
+ return rv;
+}
+
+
+/* ------------------------------ net_write ------------------------------- */
+
+#ifndef NEEDS_WRITEV
+int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Writev(fd, (PRIOVec *)iov, iov_size, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+ return rv;
+}
+
+#else /* NEEDS_WRITEV */
+
+/* Since SSL and NT do not support writev(), we just emulate it.
+ * This does not lead to the optimal number of packets going out...
+ */
+int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size)
+{
+ int index;
+
+ child_status(CHILD_WRITING);
+
+ for (index=0; index<iov_size; index++) {
+
+ /* net_write already does the buffer for nonblocked IO */
+ if ( net_write(fd, iov[index].iov_base, iov[index].iov_len) ==IO_ERROR){
+ child_status(CHILD_PROCESSING);
+ return IO_ERROR;
+ }
+ }
+
+ child_status(CHILD_PROCESSING);
+ return IO_OKAY;
+}
+#endif /* NEEDS_WRITEV */
+
+
+NSAPI_PUBLIC int net_write(SYS_NETFD fd, char *buf, int sz)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Send(fd, buf, sz, 0, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+ if(rv < 0) {
+ return IO_ERROR;
+ }
+ return rv;
+}
+
+NSAPI_PUBLIC int net_socketpair(SYS_NETFD *pair)
+{
+ return PR_NewTCPSocketPair(pair);
+}
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC SYS_NETFD net_dup2(SYS_NETFD prfd, int osfd)
+{
+ SYS_NETFD newfd = NULL;
+
+ if (prfd && PR_FileDesc2NativeHandle(prfd) != osfd) {
+ if (dup2(PR_FileDesc2NativeHandle(prfd), osfd) != -1) {
+ newfd = PR_ImportFile(osfd);
+ if (!newfd)
+ close(osfd);
+ }
+ }
+
+ return newfd;
+}
+
+NSAPI_PUBLIC int net_is_STDOUT(SYS_NETFD prfd)
+{
+ int fd = PR_FileDesc2NativeHandle(prfd);
+ if (fd == STDOUT_FILENO) return 1;
+ return 0;
+}
+
+NSAPI_PUBLIC int net_is_STDIN(SYS_NETFD prfd)
+{
+ int fd = PR_FileDesc2NativeHandle(prfd);
+ if (fd == STDIN_FILENO) return 1;
+ return 0;
+}
+
+#endif /* XP_UNIX */
+
+/* -------------------------- Accept mutex crap --------------------------- */
+
+
+#ifndef NET_WINSOCK
+
+
+#include "sem.h"
+static SEMAPHORE mob_sem;
+static int have_mob_sem;
+
+
+void net_accept_enter(void)
+{
+ if(sem_grab(mob_sem) == -1)
+ ereport(LOG_CATASTROPHE, "sem_grab failed (%s)", system_errmsg());
+ have_mob_sem = 1;
+}
+
+int net_accept_tenter(void)
+{
+ int ret = sem_tgrab(mob_sem);
+ if(ret != -1)
+ have_mob_sem = 1;
+ return ret;
+}
+
+void net_accept_exit(void)
+{
+ if(sem_release(mob_sem) == -1)
+ ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg());
+ have_mob_sem = 0;
+}
+
+#ifdef AIX
+#undef accept
+#define accept naccept
+#endif
+
+void net_accept_texit(void)
+{
+ if(have_mob_sem && (sem_release(mob_sem) == -1))
+ ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg());
+ have_mob_sem = 0;
+}
+
+int net_accept_init(int port)
+{
+ /* XXXMB how to translate this to nspr? */
+ /* since SSL_AcceptHook is no longer in ns security (HCL_1_5),
+ so this is gone! (It does exist in HCL_101)
+ SSL_AcceptHook((SSLAcceptFunc)PR_Accept);
+ */
+ have_mob_sem = 0;
+ mob_sem = sem_init("netsite", port);
+ return (mob_sem == SEM_ERROR ? -1 : 0);
+}
+
+void net_accept_terminate(void)
+{
+ sem_terminate(mob_sem);
+}
+
+#endif /* !NET_WINSOCK */
+
+
+/* ----------------------------- net_ip2host ------------------------------ */
+
+
+char *dns_ip2host(char *ip, int verify);
+
+NSAPI_PUBLIC char *net_ip2host(char *ip, int verify)
+{
+ if(!net_enabledns)
+ return NULL;
+
+ return dns_ip2host(ip, verify);
+}
+
+
+
+/* ---------------------------- util_hostname ----------------------------- */
+
+
+
+#ifdef XP_UNIX
+#include <sys/param.h>
+#else /* WIN32 */
+#define MAXHOSTNAMELEN 255
+#endif /* XP_UNIX */
+
+/* Defined in dns.c */
+char *net_find_fqdn(PRHostEnt *p);
+
+NSAPI_PUBLIC char *util_hostname(void)
+{
+ char str[MAXHOSTNAMELEN];
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+ gethostname(str, MAXHOSTNAMELEN);
+ err = PR_GetHostByName(
+ str,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ if (err == PR_FAILURE)
+ return NULL;
+ return net_find_fqdn(&hent);
+}
+
+
diff --git a/lib/base/nscperror.c b/lib/base/nscperror.c
new file mode 100644
index 00000000..9d791f89
--- /dev/null
+++ b/lib/base/nscperror.c
@@ -0,0 +1,162 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* nscperrors.c
+ * Very crude error handling for nspr and libsec.
+ */
+
+#include "netsite.h"
+
+#define NSCP_NSPR_ERROR_BASE (-6000)
+#define NSCP_NSPR_MAX_ERROR (NSCP_NSPR_ERROR_BASE + 29)
+#define NSCP_LIBSEC_ERROR_BASE (-8192)
+#define NSCP_LIBSEC_MAX_ERROR (NSCP_LIBSEC_ERROR_BASE + 63)
+#define NSCP_LIBSSL_ERROR_BASE (-12288)
+#define NSCP_LIBSSL_MAX_ERROR (NSCP_LIBSSL_ERROR_BASE + 19)
+
+typedef struct nscp_error_t {
+ int errorNumber;
+ const char *errorString;
+} nscp_error_t;
+
+nscp_error_t nscp_nspr_errors[] = {
+ { 0, "NSPR error" },
+ { 1, "Out of memory" },
+ { 2, "Bad file descriptor" },
+ { 3, "Data temporarily not available" },
+ { 4, "Access fault" },
+ { 5, "Invalid method" },
+ { 6, "Illegal access" },
+ { 7, "Unknown error" },
+ { 8, "Pending interrupt" },
+ { 9, "Not implemented" },
+ { 10, "IO error" },
+ { 11, "IO timeout error" },
+ { 12, "IO already pending error" },
+ { 13, "Directory open error" },
+ { 14, "Invalid Argument" },
+ { 15, "Address not available" },
+ { 16, "Address not supported" },
+ { 17, "Already connected" },
+ { 18, "Bad address" },
+ { 19, "Address already in use" },
+ { 20, "Connection refused" },
+ { 21, "Network unreachable" },
+ { 22, "Connection timed out" },
+ { 23, "Not connected" },
+ { 24, "Load library error" },
+ { 25, "Unload library error" },
+ { 26, "Find symbol error" },
+ { 27, "Connection reset by peer" },
+ { 28, "Range Error" },
+ { 29, "File Not Found Error" }
+};
+
+nscp_error_t nscp_libsec_errors[] = {
+ { 0, "SEC_ERROR_IO" },
+ { 1, "SEC_ERROR_LIBRARY_FAILURE" },
+ { 2, "SEC_ERROR_BAD_DATA" },
+ { 3, "SEC_ERROR_OUTPUT_LEN" },
+ { 4, "SEC_ERROR_INPUT_LEN" },
+ { 5, "SEC_ERROR_INVALID_ARGS" },
+ { 6, "SEC_ERROR_INVALID_ALGORITHM" },
+ { 7, "SEC_ERROR_INVALID_AVA" },
+ { 8, "SEC_ERROR_INVALID_TIME" },
+ { 9, "SEC_ERROR_BAD_DER" },
+ { 10, "SEC_ERROR_BAD_SIGNATURE" },
+ { 11, "SEC_ERROR_EXPIRED_CERTIFICATE" },
+ { 12, "SEC_ERROR_REVOKED_CERTIFICATE" },
+ { 13, "SEC_ERROR_UNKNOWN_ISSUER" },
+ { 14, "SEC_ERROR_BAD_KEY" },
+ { 15, "SEC_ERROR_BAD_PASSWORD" },
+ { 16, "SEC_ERROR_UNUSED" },
+ { 17, "SEC_ERROR_NO_NODELOCK" },
+ { 18, "SEC_ERROR_BAD_DATABASE" },
+ { 19, "SEC_ERROR_NO_MEMORY" },
+ { 20, "SEC_ERROR_UNTRUSTED_ISSUER" },
+ { 21, "SEC_ERROR_UNTRUSTED_CERT" },
+ { 22, "SEC_ERROR_DUPLICATE_CERT" },
+ { 23, "SEC_ERROR_DUPLICATE_CERT_TIME" },
+ { 24, "SEC_ERROR_ADDING_CERT" },
+ { 25, "SEC_ERROR_FILING_KEY" },
+ { 26, "SEC_ERROR_NO_KEY" },
+ { 27, "SEC_ERROR_CERT_VALID" },
+ { 28, "SEC_ERROR_CERT_NOT_VALID" },
+ { 29, "SEC_ERROR_CERT_NO_RESPONSE" },
+ { 30, "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE" },
+ { 31, "SEC_ERROR_CRL_EXPIRED" },
+ { 32, "SEC_ERROR_CRL_BAD_SIGNATURE" },
+ { 33, "SEC_ERROR_CRL_INVALID" },
+ { 34, "SEC_ERROR_" },
+ { 35, "SEC_ERROR_" },
+ { 36, "SEC_ERROR_" },
+ { 37, "SEC_ERROR_" },
+ { 38, "SEC_ERROR_" },
+ { 39, "SEC_ERROR_" },
+ { 40, "SEC_ERROR_" },
+ { 41, "SEC_ERROR_" },
+ { 42, "SEC_ERROR_" },
+ { 43, "SEC_ERROR_" },
+ { 44, "SEC_ERROR_" },
+ { 45, "SEC_ERROR_" },
+ { 46, "SEC_ERROR_" },
+ { 47, "SEC_ERROR_" },
+ { 48, "SEC_ERROR_" },
+ { 49, "SEC_ERROR_" },
+ { 50, "SEC_ERROR_" },
+ { 51, "SEC_ERROR_" },
+ { 52, "SEC_ERROR_" },
+ { 53, "SEC_ERROR_" },
+ { 54, "SEC_ERROR_" },
+ { 55, "SEC_ERROR_" },
+ { 56, "SEC_ERROR_" },
+ { 57, "SEC_ERROR_" },
+ { 58, "SEC_ERROR_" },
+ { 59, "SEC_ERROR_" },
+ { 60, "SEC_ERROR_" },
+ { 61, "SEC_ERROR_" },
+ { 62, "SEC_ERROR_" },
+ { 63, "SEC_ERROR_NEED_RANDOM" }
+};
+
+nscp_error_t nscp_libssl_errors[] = {
+ { 0, "SSL_ERROR_EXPORT_ONLY_SERVER" },
+ { 1, "SSL_ERROR_US_ONLY_SERVER" },
+ { 2, "SSL_ERROR_NO_CYPHER_OVERLAP" },
+ { 3, "SSL_ERROR_NO_CERTIFICATE" },
+ { 4, "SSL_ERROR_BAD_CERTIFICATE" },
+ { 5, "unused SSL error #5" },
+ { 6, "SSL_ERROR_BAD_CLIENT - the server has encountered bad data from the client." },
+ { 7, "SSL_ERROR_BAD_SERVER" },
+ { 8, "SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE" },
+ { 9, "SSL_ERROR_UNSUPPORTED_VERSION" },
+ { 10, "unused SSL error #10" },
+ { 11, "SSL_ERROR_WRONG_CERTIFICATE" },
+ { 12, "SSL_ERROR_BAD_CERT_DOMAIN" },
+ { 13, "SSL_ERROR_POST_WARNING" },
+ { 14, "SSL_ERROR_SSL2_DISABLED" },
+ { 15, "SSL_ERROR_BAD_MAC_READ - SSL has received a record with an incorrect Message Authentication Code." },
+ { 16, "SSL_ERROR_BAD_MAC_ALERT - SSL has received an error indicating an incorrect Message Authentication Code." },
+ { 17, "SSL_ERROR_BAD_CERT_ALERT - the server cannot verify your certificate." },
+ { 18, "SSL_ERROR_REVOKED_CERT_ALERT - the server has rejected your certificate as revoked." },
+ { 19, "SSL_ERROR_EXPIRED_CERT_ALERT - the server has rejected your certificate as expired." },
+};
+
+const char *
+nscperror_lookup(int error)
+{
+ if ((error >= NSCP_NSPR_ERROR_BASE) &&
+ (error <= NSCP_NSPR_MAX_ERROR)) {
+ return nscp_nspr_errors[error-NSCP_NSPR_ERROR_BASE].errorString;
+ } else if ((error >= NSCP_LIBSEC_ERROR_BASE) &&
+ (error <= NSCP_LIBSEC_MAX_ERROR)) {
+ return nscp_libsec_errors[error-NSCP_LIBSEC_ERROR_BASE].errorString;
+ } else if ((error >= NSCP_LIBSSL_ERROR_BASE) &&
+ (error <= NSCP_LIBSSL_MAX_ERROR)) {
+ return nscp_libssl_errors[error-NSCP_LIBSSL_ERROR_BASE].errorString;
+ } else {
+ return (const char *)NULL;
+ }
+}
diff --git a/lib/base/nterrors.cpp b/lib/base/nterrors.cpp
new file mode 100644
index 00000000..2eaf29b3
--- /dev/null
+++ b/lib/base/nterrors.cpp
@@ -0,0 +1,83 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * nterrors.c: Conversion of error numbers to explanation strings
+ *
+ * Aruna Victor 12/6/95
+ */
+
+
+#include <windows.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <netsite.h>
+#include <base/nterrors.h>
+#include <base/nterr.h>
+
+struct _NtHashedError {
+ int ErrorNumber;
+ char *ErrorString;
+ struct _NtHashedError *next;
+} ;
+
+typedef struct _NtHashedError NtHashedError;
+
+NtHashedError *hashedNtErrors[200];
+
+#define HASH_ERROR_MODULUS 199
+#define DEFAULT_ERROR_STRING "Error Number is unknown"
+
+char *
+FindError(int error)
+{
+ NtHashedError *tmp;
+
+ int hashValue = error % HASH_ERROR_MODULUS;
+ tmp = hashedNtErrors[hashValue];
+
+ while(tmp) {
+ if (tmp->ErrorNumber == error) {
+ return tmp->ErrorString;
+ }
+ tmp = tmp->next;
+ }
+ return(DEFAULT_ERROR_STRING);
+}
+
+void
+EnterError(NtHashedError *error)
+{
+ NtHashedError *tmp;
+ int hashValue;
+ int number = 199;
+
+ hashValue = error->ErrorNumber % HASH_ERROR_MODULUS;
+
+ if(!(tmp = hashedNtErrors[hashValue])){
+ hashedNtErrors[hashValue] = error;
+ } else {
+ while(tmp->next) {
+ tmp = tmp->next;
+ }
+ tmp->next = error;
+ }
+}
+
+void
+HashNtErrors()
+{
+ NtHashedError *error;
+ int i = 0;
+
+ while(NtErrorStrings[i].ErrorString) {
+ error = (NtHashedError *)MALLOC(sizeof(NtHashedError));
+ error->ErrorNumber = NtErrorStrings[i].ErrorNumber;
+ error->ErrorString = NtErrorStrings[i++].ErrorString;
+ error->next = NULL;
+ EnterError(error);
+ }
+} \ No newline at end of file
diff --git a/lib/base/plist.cpp b/lib/base/plist.cpp
new file mode 100644
index 00000000..fe9d909e
--- /dev/null
+++ b/lib/base/plist.cpp
@@ -0,0 +1,1154 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * MODULE: plist.c
+ *
+ * DESCRIPTION:
+ *
+ * This module implements property lists. A property list is an
+ * ordered array of property values. Each property value has an
+ * handle for some data item, and may have a reference to
+ * another property list which describes the type of the data
+ * item. Each property value has a property index which specifies
+ * its position in the property list. A property value may also
+ * have a name. Since the data item associated with a property
+ * value may reference another property list, it is possible to
+ * construct arbitrary linked structures of property lists.
+ *
+ * IMPLEMENTATION NOTES:
+ */
+
+#include "netsite.h"
+#include "base/plist.h"
+#include "plist_pvt.h"
+
+int plistHashSizes[] = PLSTSIZES;
+
+/*
+ * FUNCTION: PListAssignValue
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the value and/or type of a defined property
+ * in given property list. If the property type is specified as
+ * NULL, it is unchanged. However, the property value is always
+ * set to the specified value.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pname - the property name
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index of the referenced property is
+ * returned as the function value. Errors are indicated by a
+ * negative return code as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListAssignValue(PList_t plist, const char *pname,
+ const void *pvalue, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ int pindex;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Got a symbol table for this property list? */
+ if (pl->pl_symtab) {
+
+ /* Yes, compute hash of specified name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
+
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Name match, get property index */
+ pindex = pv->pv_pi;
+
+ /* Set the new value */
+ pv->pv_value = (char *)pvalue;
+
+ /* Set type if type is given */
+ if (ptype) pv->pv_type = (PListStruct_t *)ptype;
+
+ /* Return the property index */
+ return pindex;
+ }
+ }
+ }
+
+ /* Error - specified property name is undefined */
+ return ERRPLUNDEF;
+}
+
+/*
+ * FUNCTION: PListCreate
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list and returns a handle for
+ * it. It allows the caller to reserve a specified number of
+ * property indices at the beginning of the list, and also to limit
+ * the total number of property values that may be added to the list.
+ *
+ * ARGUMENTS:
+ *
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ * resvprop - number of reserved property indices
+ * maxprop - maximum number of properties in list
+ * (zero or negative imposes no limit)
+ * flags - unused, reserved, must be zero
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListCreate(pool_handle_t *mempool, int resvprop, int maxprop, int flags)
+{
+ PListStruct_t *plist; /* pointer to property list structure */
+ int i;
+
+ plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t));
+ if (plist) {
+
+ /* Negative maxprop is the same as zero, i.e. no limit */
+ if (maxprop < 0) maxprop = 0;
+
+ /* If resvprop and maxprop are both specified, limit resvprop */
+ if (resvprop > 0) {
+ if (maxprop && (resvprop > maxprop)) resvprop = maxprop;
+ }
+ else resvprop = 0;
+
+ /* Initialize property list structure */
+ plist->pl_mempool = mempool;
+ plist->pl_symtab = NULL;
+ plist->pl_maxprop = maxprop;
+ plist->pl_resvpi = resvprop;
+ plist->pl_initpi = resvprop;
+ plist->pl_lastpi = resvprop;
+
+ /* Set initialize size for array of property value pointers */
+ plist->pl_cursize = (resvprop) ? resvprop : PLIST_DEFSIZE;
+
+ /* Allocate the initial array of property value pointers */
+ plist->pl_ppval = (pb_entry **)pool_malloc(mempool,
+ (plist->pl_cursize *
+ sizeof(PLValueStruct_t *)));
+ if (!plist->pl_ppval) {
+
+ /* Failed - insufficient memory */
+ pool_free(mempool, (void *)plist);
+ plist = NULL;
+ }
+ else {
+ /* NULL out pointers in the reserved index range, if any */
+ for (i = 0; i < plist->pl_lastpi; ++i) {
+ plist->pl_ppval[i] = 0;
+ }
+ }
+ }
+
+ return (PList_t)plist;
+}
+
+/*
+ * FUNCTION: PListDefProp
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property in a specified property list.
+ * The 'pindex' argument may be used to request a particular property
+ * index for the new property. If 'pindex' is greater than zero,
+ * the specified value is used as the new property's index, provided
+ * there is no property at that index already. If 'pindex' is zero,
+ * then the next available property index is assigned to the new
+ * property. A name may optionally be specified for the new property.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - new property index (or zero)
+ * pname - new property name (or NULL)
+ *
+ * RETURNS:
+ *
+ * If successful, the index of the new property is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListDefProp(PList_t plist, int pindex, const char *pname, const int flags)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int cursize;
+ int i;
+ int wrapped;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Is pindex specified? */
+ if (pindex > 0) {
+
+ /* Yes, is it in the reserved range? */
+ if (flags != PLFLG_IGN_RES && pindex > pl->pl_resvpi) {
+ /* No, error */
+ return ERRPLINVPI;
+ }
+
+ i = pindex - 1;
+
+ if (ppval[i]) {
+ /* Error - property already exists at specified index */
+ return ERRPLEXIST;
+ }
+ }
+ else {
+
+ /*
+ * Look for a free property index, starting at pl_lastpi + 1.
+ * (Note that i is the property index - 1)
+ */
+ for (wrapped = 0, i = pl->pl_lastpi; ;) {
+
+ /* Are we in an initialized part of the array? */
+ if (i < pl->pl_initpi) {
+
+ /* Yes, use this index if it's free */
+ if (ppval[i] == 0) break;
+
+ /* Otherwise step to the next one */
+ ++i;
+ }
+ else {
+
+ /* Have we reached the end yet? */
+ if (i < pl->pl_cursize) {
+
+ /*
+ * We are above the highest initialized index, but
+ * still within the allocated size. An index in
+ * this range can be used with no further checks.
+ */
+ ppval[i] = 0;
+ }
+ else {
+
+ /*
+ * It's looking like time to grow the array, but
+ * first go back and look for an unused, unreserved
+ * index that might have been freed.
+ */
+ if (!wrapped) {
+
+ i = pl->pl_resvpi;
+ wrapped = 1;
+ continue;
+ }
+
+ /*
+ * Grow the array unless there is a specified maximum
+ * size and we've reached it.
+ */
+ i = pl->pl_cursize;
+ if (pl->pl_maxprop && (i > pl->pl_maxprop)) {
+
+ /* Error - property list is full */
+ return ERRPLFULL;
+ }
+
+ /* Increase planned size of list */
+ cursize = i + PLIST_DEFGROW;
+
+ /* Reallocate the array of property value pointers */
+ ppval = (PLValueStruct_t **)pool_realloc(pl->pl_mempool,
+ (void *)ppval,
+ (cursize * sizeof(PLValueStruct_t *)));
+ if (!ppval) {
+
+ /* Error - insufficient memory */
+ return ERRPLNOMEM;
+ }
+
+ /* Initialize the first new entry and select it */
+ ppval[i] = NULL;
+ pl->pl_ppval = (pb_entry **)ppval;
+ pl->pl_cursize = cursize;
+ }
+
+ /* Update the highest initialized index value */
+ pl->pl_initpi = i + 1;
+ break;
+ }
+ }
+
+ /* Set the starting point for the next allocation */
+ pl->pl_lastpi = i + 1;
+ }
+
+ /* We have a property index (i + 1). Create a new property value */
+ pv = (PLValueStruct_t *)pool_calloc(pl->pl_mempool,
+ 1, sizeof(PLValueStruct_t));
+ if (!pv) {
+
+ /* Error - insufficient memory */
+ return ERRPLNOMEM;
+ }
+
+ pv->pv_pbentry.param = &pv->pv_pbparam;
+ pv->pv_pi = i + 1;
+ ppval[i] = pv;
+
+ /* Name the property if the name was specified */
+ if (pname) {
+
+ /* XXX Maybe should delete property if naming fails */
+ return PListNameProp(plist, i + 1, pname);
+ }
+
+ /* Return the property index of the new property */
+ return i + 1;
+}
+
+/*
+ * FUNCTION: PListDeleteProp
+ *
+ * DESCRIPTION:
+ *
+ * This function deletes a property from a specified property list.
+ * The property can be specified by its property index, using a
+ * pindex value greater than zero, or by its name, by specifying
+ * pindex as zero and pname as the property name. This does not
+ * have any effect on the data referenced by the property value,
+ * if any, nor does it have any effect on the property list that
+ * describes the property value's type, if any.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index, or zero
+ * pname - the property name, or NULL
+ */
+
+NSAPI_PUBLIC const void *
+PListDeleteProp(PList_t plist, int pindex, const char *pname_in)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t **pvp;
+ PLValueStruct_t *pv = NULL;
+ int i;
+ const void *pvalue = NULL;
+ char *pname = (char *)pname_in;
+
+ if (!plist) return NULL;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Get the pointer to the property structure */
+ pv = ppval[pindex - 1];
+ pname = 0;
+ if (pv) {
+ pname = pv->pv_name;
+ }
+ }
+
+ if (pname && pl->pl_symtab) {
+
+ /* Compute hash of specified property name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pvp = &pl->pl_symtab->pt_hash[i]; *pvp; pvp = &(*pvp)->pv_next) {
+
+ pv = *pvp;
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Found it. Get its index and remove it. */
+ pindex = pv->pv_pi;
+ *pvp = pv->pv_next;
+ break;
+ }
+ }
+ }
+
+ /* Found the indicated property by index or name? */
+ if (pv) {
+
+ /* Yes, remove it from the property list */
+ ppval[pindex - 1] = NULL;
+
+ /* Free the property name, if any */
+ if (pv->pv_name) {
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+ pvalue = pv->pv_value;
+
+ /* Free the property */
+ pool_free(pl->pl_mempool, (void *)pv);
+ }
+ return(pvalue);
+}
+
+/*
+ * FUNCTION: PListFindValue
+ *
+ * DESCRIPTION:
+ *
+ * This function retrieves the value and type of a property with a
+ * specified property name. If the pvalue argument is non-NULL,
+ * it specifies a location in which to return the property value.
+ * Similarly, if ptype is non-NULL, it specifies where the property
+ * list describing the property type is to be returned. If a
+ * property has no value, the value returned for pvalue is NULL.
+ * If a property has no type, the value returned for ptype is NULL.
+ * A property can have a value, a type, both, or neither.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pname - pointer to property name string
+ * pvalue - property value return pointer
+ * ptype - property type return pointer
+ *
+ * RETURNS:
+ *
+ * If successful, the index of the referenced property is returned
+ * as the function value. Errors are indicated by a negative
+ * return code as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListFindValue(PList_t plist, const char *pname, void **pvalue, PList_t *ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ int pindex;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Got a symbol table for this property list? */
+ if (pl->pl_symtab) {
+
+ /* Yes, compute hash of specified name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
+
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Name match, get property index */
+ pindex = pv->pv_pi;
+
+ /* Return the value if requested */
+ if (pvalue) *pvalue = (void *)(pv->pv_value);
+
+ /* Return the type if requested */
+ if (ptype) *ptype = (PList_t)(pv->pv_type);
+
+ /* Return the property index */
+ return pindex;
+ }
+ }
+ }
+
+ /* Error - specified property name is undefined */
+ return ERRPLUNDEF;
+}
+
+/*
+ * FUNCTION: PListInitProp
+ *
+ * DESCRIPTION:
+ *
+ * This function combines the functions of PListDefProp() and
+ * PListSetValue(), defining a new property and assigning it an
+ * initial value and optionally a type and/or a name.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - a reserved property index, or zero
+ * pname - the new property name, or NULL
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListInitProp(PList_t plist, int pindex, const char *pname,
+ const void *pvalue, PList_t ptype)
+{
+ int rv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Create the property */
+ rv = PListDefProp(plist, pindex, pname, PLFLG_USE_RES);
+ if (rv > 0) {
+
+ /* If that worked, set the value and type */
+ rv = PListSetValue(plist, rv, pvalue, ptype);
+ }
+
+ return rv;
+}
+
+/*
+ * FUNCTION: PListNew
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list, using the specified
+ * memory pool for allocating the internal data structures used to
+ * represent it. If the mempool argument is NULL, the default
+ * memory pool is used.
+ *
+ * ARGUMENTS:
+ *
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListNew(pool_handle_t *mempool)
+{
+ /* Just call PListCreate with default parameters */
+ return PListCreate(mempool, 0, 0, 0);
+}
+
+/*
+ * FUNCTION: PListDestroy
+ *
+ * DESCRIPTION:
+ *
+ * This function destroys a specified property list. This means
+ * that any dynamic memory which was allocated as a result of calls
+ * to the property list API is freed to the memory pool from which
+ * it was allocated. Property value data is not freed, nor are
+ * any property lists associated with property types.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ */
+
+void
+PListDestroy(PList_t plist)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+
+ if (!plist) return;
+
+ /* Free the property name symbol table if any */
+ if (pl->pl_symtab) {
+ pool_free(pl->pl_mempool, (void *)(pl->pl_symtab));
+ }
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+
+ /* Free the property name string if any */
+ if (pv->pv_name) {
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+
+ /* Free the property value structure */
+ pool_free(pl->pl_mempool, (void *)pv);
+ }
+ }
+
+ /* Free the array of pointers to property values */
+ pool_free(pl->pl_mempool, (void *)ppval);
+
+ /* Free the property list head */
+ pool_free(pl->pl_mempool, (void *)pl);
+}
+
+/*
+ * FUNCTION: PListGetValue
+ *
+ * DESCRIPTION:
+ *
+ * This function retrieves the value and type of the property with
+ * the property index given by pindex in the specified property
+ * list. The pindex argument must specify the index of a defined
+ * property. If the pvalue argument is non-NULL, it specifies a
+ * location in which to return the property value. Similarly, if
+ * ptype is non-NULL, it specifies where the property list
+ * describing the property type is to be returned. If a property
+ * has no value, the value returned for pvalue is NULL. If a
+ * property has no type, the value returned for ptype is NULL. A
+ * property can have a value, a type, both, or neither.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pvalue - property value return pointer
+ * ptype - property type return pointer
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListGetValue(PList_t plist, int pindex, void **pvalue, PList_t *ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, return the value if requested */
+ if (pvalue) *pvalue = (void *)(pv->pv_value);
+
+ /* Return the type if requested */
+ if (ptype) *ptype = (PList_t)(pv->pv_type);
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListHashName
+ *
+ * DESCRIPTION:
+ *
+ * This function hashes a given property name for a specified
+ * symbol table. It produces a value that can be used as an
+ * index in the pt_hash array associated with the symbol table.
+ *
+ * ARGUMENTS:
+ *
+ * symtab - pointer to the symbol table
+ * pname - pointer to the property name string
+ *
+ * RETURNS:
+ *
+ * The hash index is returned as the function value.
+ */
+
+int
+PListHashName(PLSymbolTable_t *symtab, const char *pname)
+{
+ unsigned int hashval = 0; /* hash value */
+
+ while (*pname) {
+ hashval = (hashval<<5) ^ (*pname++ & 0x7f);
+ }
+
+ return hashval % PLSIZENDX(symtab->pt_sizendx);
+}
+
+/*
+ * FUNCTION: PListNameProp
+ *
+ * DESCRIPTION:
+ *
+ * This function assigns a name to a defined property with the
+ * property index, pindex. If the property has an existing name,
+ * it will be replaced with the name specified by pname.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pname - the new property name
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListNameProp(PList_t plist, int pindex, const char *pname)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ PLSymbolTable_t *pt;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ pt = pl->pl_symtab;
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ((PLValueStruct_t **)(pl->pl_ppval))[pindex - 1];
+ if (pv) {
+
+ /* If it has a name already, unname it */
+ if (pv->pv_name) {
+ PLValueStruct_t **pvp;
+
+ /* Get hash bucket index */
+ i = PListHashName(pt, pv->pv_name);
+
+ /* Seach hash collision list for this property */
+ for (pvp = &pt->pt_hash[i];
+ *pvp; pvp = &(*pvp)->pv_next) {
+
+ if (*pvp == pv) {
+
+ /* Remove it from the list */
+ *pvp = pv->pv_next;
+ break;
+ }
+ }
+
+ /* Free the current name string */
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+
+ /* Got a new name? */
+ if (pname) {
+
+ /* Yes, is there a hash table? */
+ if (!pt) {
+
+ /* No, create one */
+ pt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1,
+ PLHASHSIZE(0));
+ if (!pt) {
+ return ERRPLNOMEM;
+ }
+
+ pl->pl_symtab = pt;
+ }
+ else {
+
+ /* Is it time to grow the hash table? */
+ i = PLSIZENDX(pt->pt_sizendx);
+ if ((pt->pt_sizendx < PLMAXSIZENDX) &&
+ pt->pt_nsyms >= (i + i)) {
+
+ PLSymbolTable_t *npt;
+
+ /* Yes, allocate the new table */
+ npt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1,
+ PLHASHSIZE(pt->pt_sizendx+1));
+ if (npt) {
+ PLValueStruct_t *opv;
+ PLValueStruct_t *npv;
+ int j;
+
+ npt->pt_sizendx = pt->pt_sizendx + 1;
+ npt->pt_nsyms = pt->pt_nsyms;
+
+ /* Rehash all the names into the new table */
+ for (i = 0; i < PLSIZENDX(pt->pt_sizendx); ++i) {
+ for (opv = pt->pt_hash[i]; opv; opv = npv) {
+ npv = opv->pv_next;
+ j = PListHashName(npt, opv->pv_name);
+ opv->pv_next = npt->pt_hash[j];
+ npt->pt_hash[j] = opv;
+ }
+ }
+
+ pl->pl_symtab = npt;
+
+ /* Free the old symbol table */
+ pool_free(pl->pl_mempool, (void *)pt);
+ pt = npt;
+ }
+ }
+ }
+
+ /* Duplicate the name string */
+ pv->pv_name = pool_strdup(pl->pl_mempool, (char *)pname);
+
+ /* Add name to symbol table */
+ i = PListHashName(pt, pname);
+ pv->pv_next = pt->pt_hash[i];
+ pt->pt_hash[i] = pv;
+ }
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListSetType
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the property type of the defined property
+ * with the property index, pindex. The property list describing
+ * the property type is specified by ptype. If ptype is NULL,
+ * the property type will be set to be undefined (NULL).
+ *
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListSetType(PList_t plist, int pindex, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, set the new type */
+ pv->pv_type = ptype;
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListSetValue
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the value and optionally the type of a
+ * defined property in a given property list. The pindex argument
+ * specifies the property index, which must be greater than zero.
+ * The ptype argument specifies a property list that describes the
+ * property type. If ptype is NULL, the property type, if any, is
+ * unchanged by this function. However, the property value is
+ * always set to the value given by pvalue.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListSetValue(PList_t plist, int pindex, const void *pvalue, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, set the new value */
+ pv->pv_value = (char *)pvalue;
+
+ /* Set type if type is given */
+ if (ptype) pv->pv_type = (PListStruct_t *)ptype;
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListEnumerate
+ *
+ * DESCRIPTION:
+ *
+ * This function walks through a specified property list
+ * calling a user supplied function with the property
+ * name and value as parameters.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * user_func - handle for the user function
+ */
+
+NSAPI_PUBLIC void
+PListEnumerate(PList_t plist, PListFunc_t *user_func, void *user_data)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+
+ if (!plist) return;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+ (*user_func)(pv->pv_name, pv->pv_value, user_data);
+ }
+
+ }
+
+}
+
+/*
+ * FUNCTION: PListCreateDuplicate
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list and returns a handle for
+ * it. The source plist provides the new plists parameters.
+ *
+ * ARGUMENTS:
+ *
+ * src_plist - source plist to duplicate
+ * mempool - handle for a memory pool to be associated
+ * with the new property list, only
+ * used if flags is set to PLFLG_NEW_MPOOL
+ * flags - if PLFLG_NEW_MPOOL uses new_mempool
+ * parameter
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+static PList_t
+PListCreateDuplicate(PList_t src_plist, pool_handle_t *new_mempool, int flags)
+{
+ PListStruct_t *plist; /* pointer to property list structure */
+ int i;
+ pool_handle_t *mempool;
+
+ mempool = (flags == PLFLG_NEW_MPOOL) ? new_mempool : src_plist->pl_mempool;
+
+ plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t));
+ if (plist) {
+
+ /* Initialize property list structure */
+ plist->pl_mempool = mempool;
+ plist->pl_symtab = NULL;
+ plist->pl_maxprop = src_plist->pl_maxprop;
+ plist->pl_resvpi = src_plist->pl_resvpi;
+ plist->pl_initpi = src_plist->pl_initpi;
+ plist->pl_lastpi = src_plist->pl_lastpi;
+
+ /* Set initialize size for array of property value pointers */
+ plist->pl_cursize = src_plist->pl_cursize;
+
+ /* Allocate the initial array of property value pointers */
+ plist->pl_ppval = (pb_entry **)pool_malloc(mempool,
+ (plist->pl_cursize *
+ sizeof(PLValueStruct_t *)));
+ if (!plist->pl_ppval) {
+
+ /* Failed - insufficient memory */
+ pool_free(mempool, (void *)plist);
+ plist = NULL;
+ }
+ else {
+ /* NULL out pointers in the reserved index range, if any */
+ for (i = 0; i < plist->pl_lastpi; ++i) {
+ plist->pl_ppval[i] = 0;
+ }
+ }
+ }
+
+ return (PList_t)plist;
+}
+
+
+/*
+ * FUNCTION: PListDuplicate
+ *
+ * DESCRIPTION:
+ *
+ * This function duplicates a specified PList_t.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ * resvprop - number of reserved property indices
+ * maxprop - maximum number of properties in list
+ * (zero or negative imposes no limit)
+ * flags - unused, reserved, must be zero
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListDuplicate(PList_t plist, pool_handle_t *new_mempool, int flags)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+ int rv = 0;
+ PList_t new_plist;
+
+ if (!plist) return NULL;
+
+ new_plist = PListCreateDuplicate(plist, new_mempool, flags);
+ if (new_plist == NULL) {
+ return(NULL);
+ }
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+ /* Create the property */
+ rv = PListDefProp(new_plist, i + 1, pv->pv_name, PLFLG_IGN_RES);
+ if (rv > 0) {
+
+ /* If that worked, set the value and type */
+ rv = PListSetValue(new_plist, rv, pv->pv_value, pv->pv_type);
+ }
+
+ if ( rv <= 0 ) {
+ PListDestroy(new_plist);
+ return(NULL);
+ }
+ }
+
+ }
+
+ return(new_plist);
+}
+
+/*
+ * FUNCTION: PListGetPool
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the memory pool the PList is allocated from.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ *
+ * RETURNS:
+ *
+ * The memory pool address, which can be NULL.
+ */
+
+NSAPI_PUBLIC pool_handle_t *
+PListGetPool(PList_t plist)
+{
+ if (!plist) return NULL;
+
+ return(plist->pl_mempool);
+}
+
diff --git a/lib/base/plist_pvt.h b/lib/base/plist_pvt.h
new file mode 100644
index 00000000..e4b861c5
--- /dev/null
+++ b/lib/base/plist_pvt.h
@@ -0,0 +1,122 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PLIST_PVT_H
+#define _PLIST_PVT_H
+
+/*
+ * FILE: plist_pvt.h
+ *
+ * DESCRIPTION:
+ *
+ * This file contains private definitions for the property list
+ * utility implementation.
+ */
+
+#include "base/pool.h"
+
+/* Forward declarations */
+typedef struct PLValueStruct_s PLValueStruct_t;
+typedef struct PLSymbol_s PLSymbol_t;
+typedef struct PLSymbolTable_s PLSymbolTable_t;
+typedef struct PListStruct_s PListStruct_t;
+
+/*
+ * TYPE: PLValueStruct_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents a property value. It is dynamically
+ * allocated when a new property is added to a property list.
+ * It contains a reference to a property list that contains
+ * information about the property value, and a reference to
+ * the property value data.
+ */
+
+#ifndef PBLOCK_H
+#include "base/pblock.h"
+#endif /* PBLOCK_H */
+#include <stddef.h>
+
+struct PLValueStruct_s {
+ pb_entry pv_pbentry; /* used for pblock compatibility */
+ pb_param pv_pbparam; /* property name and value pointers */
+ PLValueStruct_t *pv_next; /* property name hash collision link */
+ PListStruct_t *pv_type; /* property value type reference */
+ int pv_pi; /* property index */
+ int pv_flags; /* bit flags */
+};
+
+#define pv_name pv_pbparam.name
+#define pv_value pv_pbparam.value
+
+/* pv_flags definitions */
+#define PVF_MALLOC 0x1 /* allocated via MALLOC */
+
+/* Offset to pv_pbparam in PLValueStruct_t */
+#define PVPBOFFSET offsetof(struct PLValueStruct_s,pv_pbparam)
+
+/* Convert pb_param pointer to PLValueStruct_t pointer */
+#define PATOPV(p) ((PLValueStruct_t *)((char *)(p) - PVPBOFFSET))
+
+/*
+ * TYPE: PLSymbolTable_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents a symbol table that maps property names
+ * to properties. It is dynamically allocated the first time a
+ * property is named.
+ */
+
+#define PLSTSIZES {7, 19, 31, 67, 123, 257, 513}
+#define PLMAXSIZENDX (sizeof(plistHashSizes)/sizeof(plistHashSizes[0]))
+
+struct PLSymbolTable_s {
+ int pt_sizendx; /* pt_hash size, as an index in PLSTSIZES */
+ int pt_nsyms; /* number of symbols in table */
+ PLValueStruct_t *pt_hash[1];/* variable-length array */
+};
+
+/*
+ * TYPE: PListStruct_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents the top-level of a property list structure.
+ * It is dynamically allocated when a property list is created, and
+ * freed when the property list is destroyed. It references a
+ * dynamically allocated array of pointers to property value
+ * structures (PLValueStruct_t).
+ */
+
+#define PLIST_DEFSIZE 8 /* default initial entries in pl_ppval */
+#define PLIST_DEFGROW 16 /* default incremental entries for pl_ppval */
+
+struct PListStruct_s {
+ pblock pl_pb; /* pblock subset of property list head */
+ PLSymbolTable_t *pl_symtab; /* property name to index symbol table */
+ pool_handle_t *pl_mempool; /* associated memory pool handle */
+ int pl_maxprop; /* maximum number of properties */
+ int pl_resvpi; /* number of reserved property indices */
+ int pl_lastpi; /* last allocated property index */
+ int pl_cursize; /* current size of pl_ppval in entries */
+};
+
+#define pl_initpi pl_pb.hsize /* number of pl_ppval entries initialized */
+#define pl_ppval pl_pb.ht /* pointer to array of value pointers */
+
+/* Convert pblock pointer to PListStruct_t pointer */
+#define PBTOPL(p) ((PListStruct_t *)(p))
+
+#define PLSIZENDX(i) (plistHashSizes[i])
+#define PLHASHSIZE(i) (sizeof(PLSymbolTable_t) + \
+ (PLSIZENDX(i) - 1)*sizeof(PLValueStruct_t *))
+
+extern int plistHashSizes[7];
+
+extern int PListHashName(PLSymbolTable_t *symtab, const char *pname);
+
+#endif /* _PLIST_PVT_H */
diff --git a/lib/base/pool.cpp b/lib/base/pool.cpp
new file mode 100644
index 00000000..56232e3f
--- /dev/null
+++ b/lib/base/pool.cpp
@@ -0,0 +1,654 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Generic pool handling routines.
+ *
+ * Hopefully these reduce the number of malloc/free calls.
+ *
+ *
+ * Thread warning:
+ * This implementation is thread safe. However, simultaneous
+ * mallocs/frees to the same "pool" are not safe. If you wish to
+ * use this module across multiple threads, you should define
+ * POOL_LOCKING which will make the malloc pools safe.
+ *
+ * Mike Belshe
+ * 11-20-95
+ *
+ */
+
+#include "netsite.h"
+#include "base/systems.h"
+#include "base/systhr.h"
+
+#ifdef MALLOC_POOLS
+#include "base/pool.h"
+#include "base/ereport.h"
+#include "base/session.h"
+#include "frame/req.h"
+#include "frame/http.h"
+#include "base/util.h"
+#include "base/crit.h"
+
+#include "base/dbtbase.h"
+
+#ifdef DEBUG
+#define POOL_ZERO_DEBUG
+#endif
+#undef POOL_LOCKING
+
+#define BLOCK_SIZE (32 * 1024)
+#define MAX_FREELIST_SIZE (BLOCK_SIZE * 32)
+
+/* WORD SIZE 8 sets us up for 8 byte alignment. */
+#define WORD_SIZE 8
+#undef ALIGN
+#define ALIGN(x) ( (x + WORD_SIZE-1) & (~(WORD_SIZE-1)) )
+
+/* block_t
+ * When the user allocates space, a BLOCK_SIZE (or larger) block is created in
+ * the pool. This block is used until all the space is eaten within it.
+ * When all the space is gone, a new block is created.
+ *
+ */
+typedef struct block_t {
+ char *data; /* the real alloc'd space */
+ char *start; /* first free byte in block */
+ char *end; /* ptr to end of block */
+ struct block_t *next; /* ptr to next block */
+} block_t;
+
+/* pool_t
+ * A pool is a collection of blocks. The blocks consist of multiple
+ * allocations of memory, but a single allocation cannot be freed by
+ * itself. Once the memory is allocated it is allocated until the
+ * entire pool is freed.
+ */
+typedef struct pool_t {
+#ifdef DEBUG_CACHES
+ time_t time_created;
+#endif
+#ifdef POOL_LOCKING
+ CRITICAL lock; /* lock for modifying the pool */
+#endif
+ block_t *curr_block; /* current block being used */
+ block_t *used_blocks; /* blocks that are all used up */
+ long size; /* size of memory in pool */
+ struct pool_t *next; /* known_pools list */
+} pool_t;
+
+/* known_pools
+ * Primarily for debugging, keep a list of all active malloc pools.
+ */
+static pool_t *known_pools = NULL;
+static CRITICAL known_pools_lock = NULL;
+static unsigned long pool_blocks_created = 0;
+static unsigned long pool_blocks_freed = 0;
+
+/* freelist
+ * Internally we maintain a list of free blocks which we try to pull from
+ * whenever possible. This list will never have more than MAX_FREELIST_SIZE
+ * bytes within it.
+ */
+static CRITICAL freelist_lock = NULL;
+static block_t *freelist = NULL;
+static unsigned long freelist_size = 0;
+static unsigned long freelist_max = MAX_FREELIST_SIZE;
+static int pool_disable = 0;
+
+int
+pool_internal_init()
+{
+ if (pool_disable == 0) {
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+ } else
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_poolInitMemoryPoolsDisabled_));
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+pool_init(pblock *pb, Session *sn, Request *rq)
+{
+ char *str_free_size = pblock_findval("free-size", pb);
+ char *str_pool_disable = pblock_findval("disable", pb);
+
+ if (str_free_size != NULL) {
+ if ( (freelist_max = atoi(str_free_size)) <= 0) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_poolInitFreeSize0UsingD_),
+ MAX_FREELIST_SIZE);
+ freelist_max = MAX_FREELIST_SIZE;
+ }
+ }
+
+ if (str_pool_disable && strcasecmp(str_pool_disable, "false") )
+ pool_disable = 1;
+ else
+ pool_disable = 0;
+
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+
+ return REQ_PROCEED;
+}
+
+
+static block_t *
+_create_block(int size)
+{
+ block_t *newblock = NULL;
+ long bytes = ALIGN(size);
+ block_t *free_ptr,
+ *last_free_ptr = NULL;
+
+ /* check freelist for large enough block first */
+
+ crit_enter(freelist_lock);
+ free_ptr = freelist;
+ while(free_ptr && ((free_ptr->end - free_ptr->data) < bytes)) {
+ last_free_ptr = free_ptr;
+ free_ptr = free_ptr->next;
+ }
+
+ if (free_ptr) {
+ newblock = free_ptr;
+ if (last_free_ptr)
+ last_free_ptr->next = free_ptr->next;
+ else
+ freelist = free_ptr->next;
+ freelist_size -= (newblock->end - newblock->data);
+ crit_exit(freelist_lock);
+ bytes = free_ptr->end - free_ptr->data;
+ }
+ else {
+ pool_blocks_created++;
+ crit_exit(freelist_lock);
+ if (((newblock = (block_t *)PERM_MALLOC(sizeof(block_t))) == NULL) ||
+ ((newblock->data = (char *)PERM_MALLOC(bytes)) == NULL)) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateBlockOutOfMemory_));
+ if (newblock)
+ PERM_FREE(newblock);
+ return NULL;
+ }
+ }
+ newblock->start = newblock->data;
+ newblock->end = newblock->data + bytes;
+ newblock->next = NULL;
+
+ return newblock;
+}
+
+/* Caller must hold lock for the pool */
+static void
+_free_block(block_t *block)
+{
+
+#ifdef POOL_ZERO_DEBUG
+ memset(block->data, 0xa, block->end-block->data);
+#endif /* POOL_ZERO_DEBUG */
+
+ if ((freelist_size + block->end - block->data) > freelist_max) {
+ /* Just have to delete the whole block! */
+
+ crit_enter(freelist_lock);
+ pool_blocks_freed++;
+ crit_exit(freelist_lock);
+
+ PERM_FREE(block->data);
+#ifdef POOL_ZERO_DEBUG
+ memset(block, 0xa, sizeof(block));
+#endif /* POOL_ZERO_DEBUG */
+
+ PERM_FREE(block);
+ return;
+ }
+ crit_enter(freelist_lock);
+ freelist_size += (block->end - block->data);
+ block->start = block->data;
+
+ block->next = freelist;
+ freelist = block;
+ crit_exit(freelist_lock);
+}
+
+/* ptr_in_pool()
+ * Checks to see if the given pointer is in the given pool.
+ * If true, returns a ptr to the block_t containing the ptr;
+ * otherwise returns NULL
+ */
+block_t *
+_ptr_in_pool(pool_t *pool, void *ptr)
+{
+ block_t *block_ptr = NULL;
+
+ /* try to find a block which contains this ptr */
+
+ if ( ((char *)ptr < (char *)pool->curr_block->end) &&
+ ((char *)ptr >= (char *)pool->curr_block->data) )
+ block_ptr = pool->curr_block;
+ else
+ for( block_ptr = pool->used_blocks;
+ block_ptr &&
+ (((char *)ptr >= (char *)block_ptr->end) &&
+ ((char *)ptr < (char *)block_ptr->data));
+ block_ptr = block_ptr->next);
+
+ return block_ptr;
+}
+
+
+NSAPI_PUBLIC pool_handle_t *
+pool_create()
+{
+ pool_t *newpool;
+
+ if (pool_disable)
+ return NULL;
+
+ newpool = (pool_t *)PERM_MALLOC(sizeof(pool_t));
+
+ if (newpool) {
+ /* Have to initialize now, as pools get created sometimes
+ * before pool_init can be called...
+ */
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+
+ if ( (newpool->curr_block =_create_block(BLOCK_SIZE)) == NULL) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_));
+ PERM_FREE(newpool);
+ return NULL;
+ }
+ newpool->used_blocks = NULL;
+ newpool->size = 0;
+ newpool->next = NULL;
+#ifdef POOL_LOCKING
+ newpool->lock = crit_init();
+#endif
+#ifdef DEBUG_CACHES
+ newpool->time_created = time(NULL);
+#endif
+
+ /* Add to known pools list */
+ crit_enter(known_pools_lock);
+ newpool->next = known_pools;
+ known_pools = newpool;
+ crit_exit(known_pools_lock);
+ }
+ else
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_1));
+
+ return (pool_handle_t *)newpool;
+}
+
+NSAPI_PUBLIC void
+pool_destroy(pool_handle_t *pool_handle)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ block_t *tmp_blk;
+ pool_t *last, *search;
+
+ if (pool_disable)
+ return;
+
+ crit_enter(known_pools_lock);
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ if (pool->curr_block)
+ _free_block(pool->curr_block);
+
+ while(pool->used_blocks) {
+ tmp_blk = pool->used_blocks;
+ pool->used_blocks = pool->used_blocks->next;
+ _free_block(tmp_blk);
+ }
+
+ /* Remove from the known pools list */
+ for (last = NULL, search = known_pools; search;
+ last = search, search = search->next)
+ if (search == pool)
+ break;
+ if (search) {
+ if(last)
+ last->next = search->next;
+ else
+ known_pools = search->next;
+
+ }
+
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+ crit_terminate(pool->lock);
+#endif
+ crit_exit(known_pools_lock);
+
+#ifdef POOL_ZERO_DEBUG
+ memset(pool, 0xa, sizeof(pool));
+#endif /* POOL_ZERO_DEBUG */
+
+ PERM_FREE(pool);
+
+ return;
+}
+
+
+NSAPI_PUBLIC void *
+pool_malloc(pool_handle_t *pool_handle, size_t size)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ long reqsize, blocksize;
+ char *ptr;
+
+ if (pool == NULL || pool_disable) {
+ return PERM_MALLOC(size);
+ }
+
+#ifdef DEBUG
+ if (size == 0)
+ return NULL;
+#endif
+
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ reqsize = ALIGN(size);
+ ptr = pool->curr_block->start;
+ pool->curr_block->start += reqsize;
+
+ /* does this fit into the last allocated block? */
+ if (pool->curr_block->start > pool->curr_block->end) {
+
+ /* Did not fit; time to allocate a new block */
+
+ pool->curr_block->start -= reqsize; /* keep structs in tact */
+
+ pool->curr_block->next = pool->used_blocks;
+ pool->used_blocks = pool->curr_block;
+
+ /* Allocate a chunk of memory which is a multiple of BLOCK_SIZE
+ * bytes
+ */
+ blocksize = ( (size + BLOCK_SIZE-1) / BLOCK_SIZE ) * BLOCK_SIZE;
+ if ( (pool->curr_block = _create_block(blocksize)) == NULL) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolMallocOutOfMemory_));
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+ return NULL;
+ }
+
+ ptr = pool->curr_block->start;
+ reqsize = ALIGN(size);
+ pool->curr_block->start += reqsize;
+ }
+
+ pool->size += reqsize;
+
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+ return ptr;
+}
+
+void _pool_free_error()
+{
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_freeUsedWherePermFreeShouldHaveB_));
+
+ return;
+}
+
+NSAPI_PUBLIC void
+pool_free(pool_handle_t *pool_handle, void *ptr)
+{
+ if (pool_handle == NULL || pool_disable) {
+ PERM_FREE(ptr);
+ return;
+ }
+
+#ifdef DEBUG
+ /* Just to be nice, check to see if the ptr was allocated in a pool.
+ * If not, issue a warning and do a REAL free just to make sure that
+ * we don't leak memory.
+ */
+ if ( !_ptr_in_pool((pool_t *)pool_handle, ptr) ) {
+ _pool_free_error();
+
+ PERM_FREE(ptr);
+ }
+#endif
+ return;
+}
+
+NSAPI_PUBLIC void *
+pool_calloc(pool_handle_t *pool_handle, size_t nelem, size_t elsize)
+{
+ void *ptr;
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_CALLOC(elsize * nelem);
+
+ ptr = pool_malloc(pool_handle, elsize * nelem);
+ if (ptr)
+ memset(ptr, 0, elsize * nelem);
+ return ptr;
+}
+
+NSAPI_PUBLIC void *
+pool_realloc(pool_handle_t *pool_handle, void *ptr, size_t size)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ void *newptr;
+ block_t *block_ptr;
+ int oldsize;
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_REALLOC(ptr, size);
+
+ if ( (newptr = pool_malloc(pool_handle, size)) == NULL)
+ return NULL;
+
+ /* With our structure we don't know exactly where the end
+ * of the original block is. But we do know an upper bound
+ * which is a valid ptr. Search the outstanding blocks
+ * for the block which contains this ptr, and copy...
+ */
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ if ( !(block_ptr = _ptr_in_pool(pool, ptr)) ) {
+ /* User is trying to realloc nonmalloc'd space! */
+ return newptr;
+ }
+
+ oldsize = block_ptr->end - (char *)ptr ;
+ if (oldsize > size)
+ oldsize = size;
+ memmove((char *)newptr, (char *)ptr, oldsize);
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+
+ return newptr;
+}
+
+NSAPI_PUBLIC char *
+pool_strdup(pool_handle_t *pool_handle, const char *orig_str)
+{
+ char *new_str;
+ int len = strlen(orig_str);
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_STRDUP(orig_str);
+
+ new_str = (char *)pool_malloc(pool_handle, len+1);
+
+ if (new_str)
+ memcpy(new_str, orig_str, len+1);
+
+ return new_str;
+}
+
+NSAPI_PUBLIC long
+pool_space(pool_handle_t *pool_handle)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+
+ return pool->size;
+}
+
+NSAPI_PUBLIC int pool_enabled()
+{
+#ifndef THREAD_ANY
+ /* we don't have USE_NSPR defined so systhread_getdata is undef'ed */
+ return 0;
+#else
+ if (pool_disable || (getThreadMallocKey() == -1) )
+ return 0;
+
+ if (!systhread_getdata(getThreadMallocKey()))
+ return 0;
+
+ return 1;
+#endif
+}
+
+
+/* pool_service_debug()
+ * NSAPI service routine to print state information about the existing
+ * pools. Hopefully useful in debugging.
+ *
+ */
+#define MAX_DEBUG_LINE 1024
+#ifdef DEBUG_CACHES /* XXXrobm causes entanglement in install and admserv cgis */
+NSAPI_PUBLIC int
+pool_service_debug(pblock *pb, Session *sn, Request *rq)
+{
+ char tmp_buf[MAX_DEBUG_LINE];
+ char cbuf[DEF_CTIMEBUF];
+ int len;
+ pool_t *pool_ptr;
+ block_t *block_ptr;
+ int pool_cnt, block_cnt;
+
+ param_free(pblock_remove("content-type", rq->srvhdrs));
+ pblock_nvinsert("content-type", "text/html", rq->srvhdrs);
+
+ protocol_status(sn, rq, PROTOCOL_OK, NULL);
+ protocol_start_response(sn, rq);
+
+ len = util_sprintf(tmp_buf, "<H2>Memory pool status report</H2>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Note: The 0 block in each pool is \
+the currently used block <P>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Freelist size: %d/%d<P>", freelist_size,
+ freelist_max);
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Pool disabled: %d<P>", pool_disable);
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Blocks created: %d<P> Blocks freed: %d",
+ pool_blocks_created, pool_blocks_freed);
+ net_write(sn->csd, tmp_buf, len);
+
+ /* Create an HTML table */
+ len = util_sprintf(tmp_buf, "<UL><TABLE BORDER=4>\n");
+ net_write(sn->csd, tmp_buf, len);
+ len = util_sprintf(tmp_buf, "<TH>Pool #</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+ len = util_sprintf(tmp_buf, "<TH>Pool size #</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+#ifdef DEBUG_CACHES
+ len = util_sprintf(tmp_buf, "<TH>Time Created</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+#endif
+ len = util_sprintf(tmp_buf, "<TH>Blocks</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ crit_enter(known_pools_lock);
+ for (pool_cnt = 0, pool_ptr = known_pools; pool_ptr;
+ pool_ptr = pool_ptr->next, pool_cnt++) {
+
+#ifdef POOL_LOCKING
+ crit_enter(pool_ptr->lock);
+#endif
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE,
+#ifndef DEBUG_CACHES
+"<tr align=right> <td>%d</td> <td>%d</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n",
+#else
+"<tr align=right> <td>%d</td> <td>%d</td> <td>%s</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n",
+#endif
+ pool_cnt, pool_space((pool_handle_t *)pool_ptr)
+#ifdef DEBUG_CACHES
+ , util_ctime(&(pool_ptr->time_created), cbuf, DEF_CTIMEBUF));
+#else
+ );
+#endif
+ net_write(sn->csd, tmp_buf, len);
+
+ /* Print the first block */
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\
+<tr align=right> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+</tr>\n",
+ 0, pool_ptr->curr_block->data,
+ pool_ptr->curr_block->start -pool_ptr->curr_block->data,
+ pool_ptr->curr_block->end - pool_ptr->curr_block->data);
+
+ net_write(sn->csd, tmp_buf, len);
+
+ for (block_cnt = 1, block_ptr = pool_ptr->used_blocks; block_ptr;
+ block_ptr = block_ptr->next, block_cnt++) {
+
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\
+<tr align=right> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+</tr>\n",
+ block_cnt, block_ptr->data,
+ block_ptr->start - block_ptr->data,
+ block_ptr->end - block_ptr->data);
+
+ net_write(sn->csd, tmp_buf, len);
+ }
+#ifdef POOL_LOCKING
+ crit_exit(pool_ptr->lock);
+#endif
+
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "</TABLE></TD></TR>");
+
+ net_write(sn->csd, tmp_buf, len);
+ }
+ crit_exit(known_pools_lock);
+
+ len = util_sprintf(tmp_buf, "</TABLE></UL>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ return REQ_PROCEED;
+
+}
+#endif /* 0 */
+#endif /* MALLOC_POOLS */
+
diff --git a/lib/base/rwlock.cpp b/lib/base/rwlock.cpp
new file mode 100644
index 00000000..1b99e062
--- /dev/null
+++ b/lib/base/rwlock.cpp
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdlib.h>
+#include "crit.h"
+#include "rwlock.h"
+
+/*
+ * rwLock.c
+ * Implements a shared/exclusive lock package atop the
+ * critical section/condition variables. It allows multiple
+ * shared lock holders and only one exclusive lock holder
+ * on a lock variable.
+ *
+ * NOTE : It currently favors writers over readers and writers
+ * may starve readers. It is usually preferable to allow updates
+ * if they are not as frequent. We may have to change this if
+ * the common usage pattern differs from this.
+ */
+
+typedef struct {
+ CRITICAL crit; /* Short term crit to synchronize lock ops */
+ CONDVAR readFree; /* Indicates lock is free for readers */
+ CONDVAR writeFree; /* Indicates lock is free for the writer */
+ int numReaders; /* Number of read locks held */
+ int write; /* Flag to indicate write lock held */
+ int numWriteWaiters;/* Number of threads waiting for write lock */
+} rwLock_t;
+
+/*
+ * rwlock_init()
+ * Allocate and initialize the rwlock structure and return
+ * to the caller.
+ */
+RWLOCK rwlock_Init()
+{
+ rwLock_t *rwLockP;
+
+ rwLockP = (rwLock_t *)PERM_MALLOC(sizeof(rwLock_t));
+ rwLockP->numReaders = 0;
+ rwLockP->write = 0;
+ rwLockP->numWriteWaiters = 0;
+ rwLockP->crit = crit_init();
+ rwLockP->readFree = condvar_init(rwLockP->crit);
+ rwLockP->writeFree = condvar_init(rwLockP->crit);
+ return((RWLOCK)rwLockP);
+}
+
+/*
+ * rwlock_terminate()
+ * Terminate the associated condvars and critical sections
+ */
+void rwlock_Terminate(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_terminate(rwLockP->crit);
+ condvar_terminate(rwLockP->readFree);
+ condvar_terminate(rwLockP->writeFree);
+ PERM_FREE(rwLockP);
+}
+
+/*
+ * rwlock_ReadLock -- Obtain a shared lock. The caller would
+ * block if there are writers or writeWaiters.
+ */
+void rwlock_ReadLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ while (rwLockP->write || rwLockP->numWriteWaiters != 0)
+ condvar_wait(rwLockP->readFree);
+ rwLockP->numReaders++;
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rwlock_writeLock -- Obtain an exclusive lock. The caller would
+ * block if there are other readers or a writer.
+ */
+void rwlock_WriteLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ rwLockP->numWriteWaiters++;
+ while (rwLockP->numReaders != 0 || rwLockP->write)
+ condvar_wait(rwLockP->writeFree);
+ rwLockP->numWriteWaiters--;
+ rwLockP->write = 1;
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rw_Unlock -- Releases the lock.
+ */
+void rwlock_Unlock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ if (rwLockP->write)
+ rwLockP->write = 0;
+ else
+ rwLockP->numReaders--;
+ if (rwLockP->numReaders == 0)
+ if (rwLockP->numWriteWaiters != 0)
+ condvar_notify(rwLockP->writeFree);
+ else
+ condvar_notifyAll(rwLockP->readFree);
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rwlock_DemoteLock -- Change an exclusive lock on the given lock
+ * variable into a shared lock.
+ */
+void rwlock_DemoteLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ rwLockP->numReaders = 1;
+ rwLockP->write = 0;
+ if (rwLockP->numWriteWaiters == 0)
+ condvar_notifyAll(rwLockP->readFree);
+ crit_exit(rwLockP->crit);
+}
diff --git a/lib/base/shexp.cpp b/lib/base/shexp.cpp
new file mode 100644
index 00000000..8cb2aae4
--- /dev/null
+++ b/lib/base/shexp.cpp
@@ -0,0 +1,290 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ *
+ * See shexp.h for public documentation.
+ *
+ * Rob McCool
+ *
+ */
+
+#include "shexp.h"
+#include <ctype.h> /* isalpha, tolower */
+
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+int valid_subexp(char *exp, char stop)
+{
+ register int x,y,t;
+ int nsc,np,tld;
+
+ x=0;nsc=0;tld=0;
+
+ while(exp[x] && (exp[x] != stop)) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) return INVALID_SXP;
+ else ++tld;
+ case '*':
+ case '?':
+ case '^':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(++x;exp[x] && (exp[x] != ']');++x)
+ if(exp[x] == '\\')
+ if(!exp[++x])
+ return INVALID_SXP;
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;
+ while(1) {
+ if(exp[++x] == ')')
+ return INVALID_SXP;
+ for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
+ if(exp[y] == '\\')
+ if(!exp[++y])
+ return INVALID_SXP;
+ if(!exp[y])
+ return INVALID_SXP;
+ t = valid_subexp(&exp[x],exp[y]);
+ if(t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(exp[x] == ')') {
+ break;
+ }
+ }
+ break;
+ case ')':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ if(!exp[++x])
+ return INVALID_SXP;
+ default:
+ break;
+ }
+ ++x;
+ }
+ if((!stop) && (!nsc))
+ return NON_SXP;
+ return ((exp[x] == stop) ? x : INVALID_SXP);
+}
+
+NSAPI_PUBLIC int shexp_valid(char *exp) {
+ int x;
+
+ x = valid_subexp(exp, '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+int _shexp_match(char *str, char *exp);
+
+int handle_union(char *str, char *exp)
+{
+ char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
+ register int t,p2,p1 = 1;
+ int cp;
+
+ while(1) {
+ for(cp=1;exp[cp] != ')';cp++)
+ if(exp[cp] == '\\')
+ ++cp;
+ for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
+ if(exp[p1] == '\\')
+ e2[p2++] = exp[p1++];
+ e2[p2] = exp[p1];
+ }
+ for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
+ if(_shexp_match(str,e2) == MATCH) {
+ FREE(e2);
+ return MATCH;
+ }
+ if(p1 == cp) {
+ FREE(e2);
+ return NOMATCH;
+ }
+ else ++p1;
+ }
+}
+
+
+int _shexp_match(char *str, char *exp)
+{
+ register int x,y;
+ int ret,neg;
+
+ ret = 0;
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
+ ret = ABORTED;
+ else {
+ switch(exp[y]) {
+ case '$':
+ if( (str[x]) )
+ ret = NOMATCH;
+ else
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*');
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ switch(_shexp_match(&str[x++],&exp[y])) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ ret = ABORTED;
+ break;
+ default:
+ return MATCH;
+ }
+ break;
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ ret = ABORTED;
+ break;
+ case '[':
+ if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
+ ++y;
+
+ if((isalnum(exp[y])) && (exp[y+1] == '-') &&
+ (isalnum(exp[y+2])) && (exp[y+3] == ']'))
+ {
+ int start = exp[y], end = exp[y+2];
+
+ /* Droolproofing for pinheads not included */
+ if(neg ^ ((str[x] < start) || (str[x] > end))) {
+ ret = NOMATCH;
+ break;
+ }
+ y+=3;
+ }
+ else {
+ int matched;
+
+ for(matched=0;exp[y] != ']';y++)
+ matched |= (str[x] == exp[y]);
+ if(neg ^ (!matched))
+ ret = NOMATCH;
+ }
+ break;
+ case '(':
+ return handle_union(&str[x],&exp[y]);
+ break;
+ case '?':
+ break;
+ case '\\':
+ ++y;
+ default:
+#ifdef XP_UNIX
+ if(str[x] != exp[y])
+#else /* XP_WIN32 */
+ if(strnicmp(str + x, exp + y, 1))
+#endif /* XP_WIN32 */
+ ret = NOMATCH;
+ break;
+ }
+ }
+ if(ret)
+ break;
+ }
+ return (ret ? ret : (str[x] ? NOMATCH : MATCH));
+}
+
+NSAPI_PUBLIC int shexp_match(char *str, char *xp) {
+ register int x;
+ char *exp = STRDUP(xp);
+
+ for(x=strlen(exp)-1;x;--x) {
+ if((exp[x] == '~') && (exp[x-1] != '\\')) {
+ exp[x] = '\0';
+ if(_shexp_match(str,&exp[++x]) == MATCH)
+ goto punt;
+ break;
+ }
+ }
+ if(_shexp_match(str,exp) == MATCH) {
+ FREE(exp);
+ return 0;
+ }
+
+ punt:
+ FREE(exp);
+ return 1;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp)
+{
+ switch(shexp_valid(exp)) {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+#ifdef XP_UNIX
+ return (strcmp(exp,str) ? 1 : 0);
+#else /* XP_WIN32 */
+ return (stricmp(exp,str) ? 1 : 0);
+#endif /* XP_WIN32 */
+ default:
+ return shexp_match(str, exp);
+ }
+}
+
+
+/* ---------------------------- shexp_casecmp ----------------------------- */
+
+
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp)
+{
+ char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t;
+ int ret;
+
+ for(t = lstr; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+ for(t = lexp; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+
+ switch(shexp_valid(lexp)) {
+ case INVALID_SXP:
+ ret = -1;
+ break;
+ case NON_SXP:
+ ret = (strcmp(lexp, lstr) ? 1 : 0);
+ break;
+ default:
+ ret = shexp_match(lstr, lexp);
+ }
+ FREE(lstr);
+ FREE(lexp);
+ return ret;
+}
+
diff --git a/lib/base/shmem.cpp b/lib/base/shmem.cpp
new file mode 100644
index 00000000..1ddd76d3
--- /dev/null
+++ b/lib/base/shmem.cpp
@@ -0,0 +1,127 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shmem.h: Portable abstraction for memory shared among a server's workers
+ *
+ * Rob McCool
+ */
+
+
+#include "shmem.h"
+
+#if defined (SHMEM_UNIX_MMAP)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <private/pprio.h> /* for nspr20 binary release */
+
+NSPR_BEGIN_EXTERN_C
+#include <sys/mman.h>
+NSPR_END_EXTERN_C
+
+NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose)
+{
+ shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s));
+ char *growme;
+
+ if( (ret->fd = PR_Open(name, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0666)) == NULL) {
+ PERM_FREE(ret);
+ return NULL;
+ }
+ growme = (char *) PERM_MALLOC(size);
+ ZERO(growme, size);
+ if(PR_Write(ret->fd, (char *)growme, size) < 0) {
+ PR_Close(ret->fd);
+ PERM_FREE(growme);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ PERM_FREE(growme);
+ PR_Seek(ret->fd, 0, PR_SEEK_SET);
+ if( (ret->data = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE,
+ SHMEM_MMAP_FLAGS, PR_FileDesc2NativeHandle(ret->fd), 0)) == (caddr_t) -1)
+ {
+ PR_Close(ret->fd);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ if(!expose) {
+ ret->name = NULL;
+ unlink(name);
+ }
+ else
+ ret->name = STRDUP(name);
+ ret->size = size;
+ return ret;
+}
+
+
+NSAPI_PUBLIC void shmem_free(shmem_s *region)
+{
+ if(region->name) {
+ unlink(region->name);
+ PERM_FREE(region->name);
+ }
+ munmap((char *)region->data, region->size); /* CLEARLY, C++ SUCKS */
+ PR_Close(region->fd);
+ PERM_FREE(region);
+}
+
+#elif defined (SHMEM_WIN32_MMAP)
+
+#define PAGE_SIZE (1024*8)
+#define ALIGN(x) ( (x+PAGE_SIZE-1) & (~(PAGE_SIZE-1)) )
+NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose)
+{
+ shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s));
+ HANDLE fHandle;
+
+ ret->fd = 0; /* not used on NT */
+
+ size = ALIGN(size);
+ if( !(ret->fdmap = CreateFileMapping(
+ (HANDLE)0xffffffff,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ size,
+ name)) )
+ {
+ int err = GetLastError();
+ PERM_FREE(ret);
+ return NULL;
+ }
+ if( !(ret->data = (char *)MapViewOfFile (
+ ret->fdmap,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ 0)) )
+ {
+ CloseHandle(ret->fdmap);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ ret->size = size;
+ ret->name = NULL;
+
+ return ret;
+}
+
+
+NSAPI_PUBLIC void shmem_free(shmem_s *region)
+{
+ if(region->name) {
+ DeleteFile(region->name);
+ PERM_FREE(region->name);
+ }
+ UnmapViewOfFile(region->data);
+ CloseHandle(region->fdmap);
+ PERM_FREE(region);
+}
+
+#endif /* SHMEM_WIN32_MMAP */
diff --git a/lib/base/system.cpp b/lib/base/system.cpp
new file mode 100644
index 00000000..e58538b4
--- /dev/null
+++ b/lib/base/system.cpp
@@ -0,0 +1,264 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * system.c: A grab bag of system-level abstractions
+ *
+ * Many authors
+ */
+
+#include "netsite.h"
+#include "base/nsassert.h"
+#include "base/ereport.h"
+
+#ifdef XP_WIN32
+#include <windows.h>
+static char *version = "Netscape Server/2.0";
+#endif
+
+#include "base/systems.h" /* find out if we have malloc pools */
+
+static int thread_malloc_key = -1;
+
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+#include "base/pool.h"
+#include "base/systhr.h"
+
+#define MALLOC_KEY \
+ ((pool_handle_t *)(thread_malloc_key != -1 ? systhread_getdata(thread_malloc_key) : NULL))
+
+#endif
+
+
+#ifdef MCC_DEBUG
+#define DEBUG_MALLOC
+#endif
+
+#ifdef DEBUG_MALLOC
+
+/* The debug malloc routines provide several functions:
+ *
+ * - detect allocated memory overflow/underflow
+ * - detect multiple frees
+ * - intentionally clobbers malloc'd buffers
+ * - intentionally clobbers freed buffers
+ */
+#define DEBUG_MAGIC 0x12345678
+#define DEBUG_MARGIN 32
+#define DEBUG_MARGIN_CHAR '*'
+#define DEBUG_MALLOC_CHAR '.'
+#define DEBUG_FREE_CHAR 'X'
+#endif /* DEBUG_MALLOC */
+
+/* On NT, the server version string is not statically encoded based
+ * upon a product compile define but dynamically set by the server
+ * exe at startup.
+ */
+
+NSAPI_PUBLIC char *system_version()
+{
+#ifdef XP_WIN32
+ return version;
+#else /* XP_UNIX */
+ return MAGNUS_VERSION_STRING;
+#endif /* XP_UNIX */
+}
+
+NSAPI_PUBLIC void system_version_set(char *server_version)
+{
+#ifdef XP_WIN32
+ version = PERM_STRDUP(server_version);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_malloc(int size)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_malloc(MALLOC_KEY, size);
+#else
+ return malloc(size);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_calloc(int size)
+{
+ void *ret;
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ ret = pool_malloc(MALLOC_KEY, size);
+#else
+ ret = malloc(size);
+#endif
+ if(ret)
+ ZERO(ret, size);
+ return ret;
+}
+
+
+NSAPI_PUBLIC void *system_realloc(void *ptr, int size)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_realloc(MALLOC_KEY, ptr, size);
+#else
+ return realloc(ptr, size);
+#endif
+}
+
+
+NSAPI_PUBLIC void system_free(void *ptr)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ pool_free(MALLOC_KEY, ptr);
+#else
+ NS_ASSERT(ptr);
+ free(ptr);
+#endif
+}
+
+NSAPI_PUBLIC char *system_strdup(const char *ptr)
+{
+ NS_ASSERT(ptr);
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_strdup(MALLOC_KEY, ptr);
+#else
+ return strdup(ptr);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_malloc_perm(int size)
+{
+#ifndef DEBUG_MALLOC
+ return malloc(size);
+#else
+ char *ptr = (char *)malloc(size + 2*DEBUG_MARGIN+2*sizeof(int));
+ char *real_ptr;
+ int *magic;
+ int *length;
+
+ magic = (int *)ptr;
+ *magic = DEBUG_MAGIC;
+ ptr += sizeof(int);
+ length = (int *)ptr;
+ *length = size;
+ ptr += sizeof(int);
+ memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN);
+ ptr += DEBUG_MARGIN;
+ memset(ptr, DEBUG_MALLOC_CHAR, size);
+ real_ptr = ptr;
+ ptr += size;
+ memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN);
+
+ return real_ptr;
+#endif
+}
+
+NSAPI_PUBLIC void *system_calloc_perm(int size)
+{
+ void *ret = system_malloc_perm(size);
+ if(ret)
+ ZERO(ret, size);
+ return ret;
+}
+
+NSAPI_PUBLIC void *system_realloc_perm(void *ptr, int size)
+{
+#ifndef DEBUG_MALLOC
+ return realloc(ptr, size);
+#else
+ int *magic, *length;
+ char *baseptr;
+ char *cptr;
+
+ cptr = (char *)ptr - DEBUG_MARGIN - 2 * sizeof(int);
+ magic = (int *)cptr;
+ if (*magic == DEBUG_MAGIC) {
+ cptr += sizeof(int);
+ length = (int *)cptr;
+ if (*length < size) {
+ char *newptr = (char *)system_malloc_perm(size);
+ memcpy(newptr, ptr, *length);
+ system_free_perm(ptr);
+
+ return newptr;
+ }else {
+ return ptr;
+ }
+ } else {
+ ereport(LOG_WARN, "realloc: attempt to realloc to smaller size");
+ return realloc(ptr, size);
+ }
+
+#endif
+}
+
+NSAPI_PUBLIC void system_free_perm(void *ptr)
+{
+#ifdef DEBUG_MALLOC
+ int *length, *magic;
+ char *baseptr, *cptr;
+ int index;
+
+ NS_ASSERT(ptr);
+
+ cptr = baseptr = ((char *)ptr) - DEBUG_MARGIN - 2*sizeof(int);
+
+ magic = (int *)cptr;
+ if (*magic == DEBUG_MAGIC) {
+ cptr += sizeof(int);
+
+ length = (int *)cptr;
+
+ cptr += sizeof(int);
+ for (index=0; index<DEBUG_MARGIN; index++)
+ if (cptr[index] != DEBUG_MARGIN_CHAR) {
+ ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)");
+ break;
+ }
+
+ cptr += DEBUG_MARGIN + *length;
+ for (index=0; index<DEBUG_MARGIN; index++)
+ if (cptr[index] != DEBUG_MARGIN_CHAR) {
+ ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)");
+ break;
+ }
+
+ memset(baseptr, DEBUG_FREE_CHAR, *length + 2*DEBUG_MARGIN+sizeof(int));
+ } else {
+ ereport(LOG_CATASTROPHE, "free: freeing unallocated memory");
+ }
+ free(baseptr);
+#else
+ free(ptr);
+#endif
+}
+
+NSAPI_PUBLIC char *system_strdup_perm(const char *ptr)
+{
+#ifndef DEBUG_MALLOC
+ NS_ASSERT(ptr);
+ return strdup(ptr);
+#else
+ int len = strlen(ptr);
+ char *nptr = (char *)system_malloc_perm(len+1);
+ memcpy(nptr, ptr, len);
+ nptr[len] = '\0';
+ return nptr;
+#endif
+}
+
+NSAPI_PUBLIC int
+getThreadMallocKey(void)
+{
+ return thread_malloc_key;
+}
+
+void
+setThreadMallocKey(int key)
+{
+ thread_malloc_key = key;
+}
+
diff --git a/lib/base/systhr.cpp b/lib/base/systhr.cpp
new file mode 100644
index 00000000..ac29121a
--- /dev/null
+++ b/lib/base/systhr.cpp
@@ -0,0 +1,256 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * systhr.c: Abstracted threading mechanisms
+ *
+ * Rob McCool
+ */
+
+#include "systhr.h"
+#include "ereport.h"
+
+#define USE_NSPR
+#ifdef USE_NSPR
+#include "nspr.h"
+#include "private/prpriv.h"
+extern "C" {
+int32 PR_GetSysfdTableMax(void);
+int32 PR_SetSysfdTableSize(int table_size);
+}
+#endif
+#include "systems.h"
+
+#ifdef THREAD_WIN32
+#include <process.h>
+
+typedef struct {
+ HANDLE hand;
+ DWORD id;
+} sys_thread_s;
+
+#endif
+
+
+
+#if defined (USE_NSPR)
+
+
+#define DEFAULT_STACKSIZE (64*1024)
+
+static unsigned long _systhr_stacksize = DEFAULT_STACKSIZE;
+
+NSAPI_PUBLIC
+void systhread_set_default_stacksize(unsigned long size)
+{
+ _systhr_stacksize = size;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC SYS_THREAD
+#ifdef UnixWare /* for ANSI C++ standard, see base/systrh.h */
+systhread_start(int prio, int stksz, ArgFn_systhread_start fn, void *arg)
+#else
+systhread_start(int prio, int stksz, void (*fn)(void *), void *arg)
+#endif
+{
+#if (defined(Linux) || defined(SNI) || defined(UnixWare)) && !defined(USE_PTHREADS)
+ prio /= 8; /* quick and dirty fix for user thread priority scale problem */
+ if (prio > 3) prio = 3;
+#endif
+
+ PRThread *ret = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))fn,
+ (void *)arg, (PRThreadPriority)prio,
+ PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ stksz ? stksz : _systhr_stacksize);
+ return (void *) ret;
+}
+
+NSPR_END_EXTERN_C
+
+
+NSAPI_PUBLIC SYS_THREAD systhread_current(void)
+{
+ return PR_GetCurrentThread();
+}
+
+NSAPI_PUBLIC void systhread_yield(void)
+{
+ /* PR_Yield(); */
+ PR_Sleep(PR_INTERVAL_NO_WAIT);
+}
+
+
+NSAPI_PUBLIC void systhread_timerset(int usec)
+{
+ /* This is an interesting problem. If you ever do turn on interrupts
+ * on the server, you're in for lots of fun with NSPR Threads
+ PR_StartEvents(usec); */
+}
+
+
+NSAPI_PUBLIC
+SYS_THREAD systhread_attach(void)
+{
+ PRThread *ret;
+ ret = PR_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL);
+
+ return (void *) ret;
+}
+
+NSAPI_PUBLIC
+void systhread_detach(SYS_THREAD thr)
+{
+ /* XXXMB - this is not correct! */
+ PR_DetachThread();
+}
+
+NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr)
+{
+
+ /* Should never be here. PR_DestroyThread is no
+ * longer used. */
+ PR_ASSERT(0);
+
+ /* PR_DestroyThread((PRThread *) thr); */
+}
+
+NSAPI_PUBLIC void systhread_sleep(int milliseconds)
+{
+ PR_Sleep(milliseconds);
+}
+
+NSAPI_PUBLIC void systhread_init(char *name)
+{
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
+#ifdef XP_UNIX
+ /* XXXrobm allocate all the fd's we can... */
+ PR_SetSysfdTableSize(PR_GetSysfdTableMax());
+#endif
+}
+
+
+NSAPI_PUBLIC int systhread_newkey()
+{
+ uintn newkey;
+
+ PR_NewThreadPrivateIndex(&newkey, NULL);
+ return (newkey);
+}
+
+NSAPI_PUBLIC void *systhread_getdata(int key)
+{
+ return PR_GetThreadPrivate(key);
+}
+
+NSAPI_PUBLIC void systhread_setdata(int key, void *data)
+{
+ PR_SetThreadPrivate(key, data);
+}
+
+/*
+ * Drag in the Java code, so our dynamic library full of it works
+ * i.e. force these symbols to load.
+ */
+NSAPI_PUBLIC void systhread_dummy(void)
+{
+
+#ifndef NSPR20
+ /* nspr/gc.c */
+ PR_InitGC(0,0);
+ /* nspr/prsystem.c */
+ PR_GetSystemInfo(PR_SI_SYSNAME, 0, 0);
+ /* nspr/linker.c */
+ PR_GetLibName(0, 0);
+ /* nspr/file.c */
+ PR_Mkdir(0, 0);
+ /* nspr/prnetdb.c */
+ PR_gethostbyname(0, 0, 0, 0, 0);
+ /* nspr/longlong.c */
+ LL_TO_S(LL_ZERO, 0, NULL, 0);
+#endif /* NSPR20 */
+}
+
+#elif defined(THREAD_WIN32)
+
+#include <nspr/prthread.h>
+#define DEFAULT_STACKSIZE 262144
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC
+SYS_THREAD systhread_start(int prio, int stksz, void (*fn)(void *), void *arg)
+{
+ sys_thread_s *ret = (sys_thread_s *) MALLOC(sizeof(sys_thread_s));
+
+ if ((ret->hand = (HANDLE)_beginthreadex(NULL, stksz, (unsigned (__stdcall *)(void *))fn,
+ arg, 0, &ret->id)) == 0) {
+ FREE(ret);
+ return NULL;
+ }
+ return (void *)ret;
+}
+
+NSPR_END_EXTERN_C
+
+NSAPI_PUBLIC SYS_THREAD systhread_current(void)
+{
+ /* XXXrobm this is busted.... */
+ return GetCurrentThread();
+}
+
+NSAPI_PUBLIC void systhread_timerset(int usec)
+{
+}
+
+NSAPI_PUBLIC SYS_THREAD systhread_attach(void)
+{
+ return NULL;
+}
+
+NSAPI_PUBLIC void systhread_yield(void)
+{
+ systhread_sleep(0);
+}
+
+NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr)
+{
+ TerminateThread(((sys_thread_s *)thr)->hand, 0);
+}
+
+
+NSAPI_PUBLIC void systhread_sleep(int milliseconds)
+{
+ /* XXXrobm there must be a better way to do this */
+ HANDLE sem = CreateSemaphore(NULL, 1, 4, "sleeper");
+ WaitForSingleObject(sem, INFINITE);
+ WaitForSingleObject(sem, milliseconds);
+ CloseHandle(sem);
+}
+
+NSAPI_PUBLIC void systhread_init(char *name)
+{
+ PR_Init(PR_USER_THREAD, 1, 0);
+}
+
+
+NSAPI_PUBLIC int systhread_newkey()
+{
+ return TlsAlloc();
+}
+
+NSAPI_PUBLIC void *systhread_getdata(int key)
+{
+ return (void *)TlsGetValue(key);
+}
+
+NSAPI_PUBLIC void systhread_setdata(int key, void *data)
+{
+ TlsSetValue(key, data);
+}
+
+#endif
+
diff --git a/lib/base/util.cpp b/lib/base/util.cpp
new file mode 100644
index 00000000..55d6ca56
--- /dev/null
+++ b/lib/base/util.cpp
@@ -0,0 +1,1449 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * util.c: A hodge podge of utility functions and standard functions which
+ * are unavailable on certain systems
+ *
+ * Rob McCool
+ */
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include "prthread.h"
+#endif /* XP_UNIX */
+
+#include "base/util.h"
+
+#include "base/dbtbase.h"
+#include "base/ereport.h"
+
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#endif /* WIN32 */
+
+/* ----------------------------- util_getline ----------------------------- */
+
+#define LF 10
+#define CR 13
+
+NSAPI_PUBLIC int util_getline(filebuf_t *buf, int lineno, int maxlen, char *l) {
+ int i, x;
+
+ x = 0;
+ while(1) {
+ i = filebuf_getc(buf);
+ switch(i) {
+ case IO_EOF:
+ l[x] = '\0';
+ return 1;
+ case LF:
+ if(x && (l[x-1] == '\\')) {
+ --x;
+ continue;
+ }
+ l[x] = '\0';
+ return 0;
+ case IO_ERROR:
+ util_sprintf(l, "I/O error reading file at line %d", lineno);
+ return -1;
+ case CR:
+ continue;
+ default:
+ l[x] = (char) i;
+ if(++x == maxlen) {
+ util_sprintf(l, "line %d is too long", lineno);
+ return -1;
+ }
+ break;
+ }
+ }
+}
+
+
+/* ---------------------------- util_can_exec ----------------------------- */
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC int util_can_exec(struct stat *fi, uid_t uid, gid_t gid)
+{
+ if(!uid)
+ return 1;
+ if((fi->st_mode & S_IXOTH) ||
+ ((gid == fi->st_gid) && (fi->st_mode & S_IXGRP)) ||
+ ((uid == fi->st_uid) && (fi->st_mode & S_IXUSR)))
+ return 1;
+ return 0;
+}
+#endif /* XP_UNIX */
+
+
+/* --------------------------- util_env_create ---------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos)
+{
+ int x;
+
+ if(!env) {
+ *pos = 0;
+ return (char **) MALLOC((n + 1)*sizeof(char *));
+ }
+ else {
+ for(x = 0; (env[x]); x++);
+ env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *)));
+ *pos = x;
+ return env;
+ }
+}
+
+
+/* ---------------------------- util_env_free ----------------------------- */
+
+
+NSAPI_PUBLIC void util_env_free(char **env)
+{
+ register char **ep = env;
+
+ for(ep = env; *ep; ep++)
+ FREE(*ep);
+ FREE(env);
+}
+
+/* ----------------------------- util_env_str ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_str(char *name, char *value) {
+ char *t,*tp;
+
+ t = (char *) MALLOC(strlen(name)+strlen(value)+2); /* 2: '=' and '\0' */
+
+ for(tp=t; (*tp = *name); tp++,name++);
+ for(*tp++ = '='; (*tp = *value); tp++,value++);
+ return t;
+}
+
+
+/* --------------------------- util_env_replace --------------------------- */
+
+
+NSAPI_PUBLIC void util_env_replace(char **env, char *name, char *value)
+{
+ int x, y, z;
+ char *i;
+
+ for(x = 0; env[x]; x++) {
+ i = strchr(env[x], '=');
+ *i = '\0';
+ if(!strcmp(env[x], name)) {
+ y = strlen(env[x]);
+ z = strlen(value);
+
+ env[x] = (char *) REALLOC(env[x], y + z + 2);
+ util_sprintf(&env[x][y], "=%s", value);
+ return;
+ }
+ *i = '=';
+ }
+}
+
+
+/* ---------------------------- util_env_find ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_find(char **env, char *name)
+{
+ char *i;
+ int x, r;
+
+ for(x = 0; env[x]; x++) {
+ i = strchr(env[x], '=');
+ *i = '\0';
+ r = !strcmp(env[x], name);
+ *i = '=';
+ if(r)
+ return i + 1;
+ }
+ return NULL;
+}
+
+
+/* ---------------------------- util_env_copy ----------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_copy(char **src, char **dst)
+{
+ char **src_ptr;
+ int src_cnt;
+ int index;
+
+ if (!src)
+ return NULL;
+
+ for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++);
+
+ if (!src_cnt)
+ return NULL;
+
+ dst = util_env_create(dst, src_cnt, &index);
+
+ for (src_ptr = src, index=0; *src_ptr; index++, src_ptr++)
+ dst[index] = STRDUP(*src_ptr);
+ dst[index] = NULL;
+
+ return dst;
+}
+
+/* ---------------------------- util_hostname ----------------------------- */
+
+
+/*
+ * MOVED TO NET.C TO AVOID INTERDEPENDENCIES
+ */
+
+
+/* --------------------------- util_chdir2path ---------------------------- */
+
+
+NSAPI_PUBLIC int util_chdir2path(char *path)
+{
+ /* use FILE_PATHSEP to accomodate WIN32 */
+ char *t = strrchr(path, FILE_PATHSEP);
+ int ret;
+
+ if(!t)
+ return -1;
+
+ *t = '\0';
+#ifdef XP_UNIX
+ ret = chdir(path);
+#else /* WIN32 */
+ ret = SetCurrentDirectory(path);
+#endif /* XP_UNIX */
+
+ /* use FILE_PATHSEP instead of chdir to accomodate WIN32 */
+ *t = FILE_PATHSEP;
+
+ return ret;
+}
+
+
+/* --------------------------- util_is_mozilla ---------------------------- */
+
+
+NSAPI_PUBLIC int util_is_mozilla(char *ua, char *major, char *minor)
+{
+ if((!ua) || strncasecmp(ua, "Mozilla/", 8))
+ return 0;
+
+ /* Major version. I punted on supporting versions like 10.0 */
+ if(ua[8] > major[0])
+ return 1;
+ else if((ua[8] < major[0]) || (ua[9] != '.'))
+ return 0;
+
+ /* Minor version. Support version numbers like 0.96 */
+ if(ua[10] < minor[0])
+ return 0;
+ else if((ua[10] > minor[0]) || (!minor[1]))
+ return 1;
+
+ if((!isdigit(ua[11])) || (ua[11] < minor[1]))
+ return 0;
+ else
+ return 1;
+}
+
+
+/* ----------------------------- util_is_url ------------------------------ */
+
+
+#include <ctype.h> /* isalpha */
+
+NSAPI_PUBLIC int util_is_url(char *url)
+{
+ char *t = url;
+
+ while(*t) {
+ if(*t == ':')
+ return 1;
+ if(!isalpha(*t))
+ return 0;
+ ++t;
+ }
+ return 0;
+}
+
+
+/* --------------------------- util_later_than ---------------------------- */
+
+
+int _mstr2num(char *str) {
+ if(!strcasecmp(str, "Jan")) return 0;
+ if(!strcasecmp(str, "Feb")) return 1;
+ if(!strcasecmp(str, "Mar")) return 2;
+ if(!strcasecmp(str, "Apr")) return 3;
+ if(!strcasecmp(str, "May")) return 4;
+ if(!strcasecmp(str, "Jun")) return 5;
+ if(!strcasecmp(str, "Jul")) return 6;
+ if(!strcasecmp(str, "Aug")) return 7;
+ if(!strcasecmp(str, "Sep")) return 8;
+ if(!strcasecmp(str, "Oct")) return 9;
+ if(!strcasecmp(str, "Nov")) return 10;
+ if(!strcasecmp(str, "Dec")) return 11;
+ return -1;
+}
+
+int _time_compare(struct tm *lms, char *ims, int later_than_op)
+{
+ int y = 0, mnum = 0, d = 0, h = 0, m = 0, s = 0, x;
+ char t[128];
+
+ /* Supported formats start with weekday (which we don't care about) */
+ /* The sizeof(t) is to avoid buffer overflow with t */
+ if((!(ims = strchr(ims,' '))) || (strlen(ims) > (sizeof(t) - 2)))
+ return 0;
+
+ while(*ims && isspace(*ims)) ++ims;
+ if((!(*ims)) || (strlen(ims) < 2))
+ return 0;
+
+ /* Standard HTTP (RFC 850) starts with dd-mon-yy */
+ if(ims[2] == '-') {
+ sscanf(ims, "%s %d:%d:%d", t, &h, &m, &s);
+ if(strlen(t) < 6)
+ return 0;
+ t[2] = '\0';
+ t[6] = '\0';
+ d = atoi(t);
+ mnum = _mstr2num(&t[3]);
+ x = atoi(&t[7]);
+ /* Postpone wraparound until 2070 */
+ y = x + (x < 70 ? 2000 : 1900);
+ }
+ /* The ctime format starts with a month name */
+ else if(isalpha(*ims)) {
+ sscanf(ims,"%s %d %d:%d:%d %*s %d", t, &d, &h, &m, &s, &y);
+ mnum = _mstr2num(t);
+ }
+ /* RFC 822 */
+ else {
+ sscanf(ims, "%d %s %d %d:%d:%d", &d, t, &y, &h, &m, &s);
+ mnum = _mstr2num(t);
+ }
+
+ if (later_than_op) {
+ if( (x = (1900 + lms->tm_year) - y) )
+ return x < 0;
+
+ if(mnum == -1)
+ return 0;
+
+ /* XXXMB - this will fail if you check if december 31 1996 is later
+ * than january 1 1997
+ */
+ if((x = lms->tm_mon - mnum) || (x = lms->tm_mday - d) ||
+ (x = lms->tm_hour - h) || (x = lms->tm_min - m) ||
+ (x = lms->tm_sec - s))
+ return x < 0;
+
+ return 1;
+ }
+ else {
+ return (mnum != -1 &&
+ 1900 + lms->tm_year == y &&
+ lms->tm_mon == mnum &&
+ lms->tm_mday == d &&
+ lms->tm_hour == h &&
+ lms->tm_min == m &&
+ lms->tm_sec == s);
+ }
+}
+
+
+/* Returns 0 if lms later than ims
+ * Returns 1 if equal
+ * Returns 1 if ims later than lms
+ */
+NSAPI_PUBLIC int util_later_than(struct tm *lms, char *ims)
+{
+ return _time_compare(lms, ims, 1);
+}
+
+
+NSAPI_PUBLIC int util_time_equal(struct tm *lms, char *ims)
+{
+ return _time_compare(lms, ims, 0);
+}
+
+/* util_str_time_equal()
+ *
+ * Function to compare if two time strings are equal
+ *
+ * Acceptible date formats:
+ * Saturday, 17-Feb-96 19:41:34 GMT <RFC850>
+ * Sat, 17 Mar 1996 19:41:34 GMT <RFC1123>
+ *
+ * Argument t1 MUST be RFC1123 format.
+ *
+ * Note- it is not the intention of this routine to *always* match
+ * There are cases where we would return != when the strings might
+ * be equal (especially with case). The converse should not be true.
+ *
+ * Return 0 if equal, -1 if not equal.
+ */
+#define MINIMUM_LENGTH 18
+#define RFC1123_DAY 5
+#define RFC1123_MONTH 8
+#define RFC1123_YEAR 12
+#define RFC1123_HOUR 17
+#define RFC1123_MINUTE 20
+#define RFC1123_SECOND 23
+NSAPI_PUBLIC int util_str_time_equal(char *t1, char *t2)
+{
+ int index;
+
+ /* skip over leading whitespace... */
+ while(*t1 && isspace(*t1)) ++t1;
+ while(*t2 && isspace(*t2)) ++t2;
+
+ /* Check weekday */
+ if ( (t1[0] != t2[0]) || (t1[1] != t2[1]) )
+ return -1;
+
+ /* Skip to date */
+ while(*t2 && !isspace(*t2)) ++t2;
+ t2++;
+
+ /* skip if not strings not long enough */
+ if ( (strlen(t1) < MINIMUM_LENGTH) || (strlen(t2) < MINIMUM_LENGTH) )
+ return -1;
+
+ if ( (t1[RFC1123_DAY] != t2[0]) || (t1[RFC1123_DAY+1] != t2[1]) )
+ return -1;
+
+ /* Skip to the month */
+ t2 += 3;
+
+ if ( (t1[RFC1123_MONTH] != t2[0]) || (t1[RFC1123_MONTH+1] != t2[1]) ||
+ (t1[RFC1123_MONTH+2] != t2[2]) )
+ return -1;
+
+ /* Skip to year */
+ t2 += 4;
+
+ if ( (t1[RFC1123_YEAR] != t2[0]) ) {
+ /* Assume t2 is RFC 850 format */
+ if ( (t1[RFC1123_YEAR+2] != t2[0]) || (t1[RFC1123_YEAR+3] != t2[1]) )
+ return -1;
+
+ /* skip to hour */
+ t2 += 3;
+ } else {
+ /* Assume t2 is RFC 1123 format */
+ if ( (t1[RFC1123_YEAR+1] != t2[1]) || (t1[RFC1123_YEAR+2] != t2[2]) ||
+ (t1[RFC1123_YEAR+3] != t2[3]) )
+ return -1;
+
+ /* skip to hour */
+ t2 += 5;
+ }
+
+ /* check date */
+ for (index=0; index<8; index++) {
+ if ( t1[RFC1123_HOUR+index] != t2[index] )
+ return -1;
+ }
+
+ /* Ignore timezone */
+
+ return 0;
+}
+
+
+/* --------------------------- util_uri_is_evil --------------------------- */
+
+
+NSAPI_PUBLIC int util_uri_is_evil(char *t)
+{
+ register int x;
+
+ for(x = 0; t[x]; ++x) {
+ if(t[x] == '/') {
+ if(t[x+1] == '/')
+ return 1;
+ if(t[x+1] == '.') {
+ switch(t[x+2]) {
+ case '.':
+ if((!t[x+3]) || (t[x+3] == '/'))
+ return 1;
+ case '/':
+ case '\0':
+ return 1;
+ }
+ }
+ }
+#ifdef XP_WIN32
+ /* On NT, the directory "abc...." is the same as "abc"
+ * The only cheap way to catch this globally is to disallow
+ * names with the trailing "."s. Hopefully this is not over
+ * restrictive
+ */
+ if ((t[x] == '.') && ( (t[x+1] == '/') || (t[x+1] == '\0') )) {
+ return 1;
+ }
+#endif
+ }
+ return 0;
+}
+
+/* ---------------------------- util_uri_parse ---------------------------- */
+
+NSAPI_PUBLIC void util_uri_parse(char *uri)
+{
+ int spos = 0, tpos = 0;
+ int l = strlen(uri);
+
+ while(uri[spos]) {
+ if(uri[spos] == '/') {
+ if((spos != l) && (uri[spos+1] == '.')) {
+ if(uri[spos+2] == '/')
+ spos += 2;
+ else
+ if((spos <= (l-3)) &&
+ (uri[spos+2] == '.') && (uri[spos+3] == '/')) {
+ spos += 3;
+ while((tpos > 0) && (uri[--tpos] != '/'))
+ uri[tpos] = '\0';
+ } else
+ uri[tpos++] = uri[spos++];
+ } else {
+ if(uri[spos+1] != '/')
+ uri[tpos++] = uri[spos++];
+ else
+ spos++;
+ }
+ } else
+ uri[tpos++] = uri[spos++];
+ }
+ uri[tpos] = '\0';
+}
+
+
+/* -------------------- util_uri_unescape_and_normalize -------------------- */
+
+#ifdef XP_WIN32
+/* The server calls this function to unescape the URI and also normalize
+ * the uri. Normalizing the uri converts all "\" characters in the URI
+ * and pathinfo portion to "/". Does not touch "\" in query strings.
+ */
+void util_uri_unescape_and_normalize(char *s)
+{
+ char *t, *u;
+
+ for(t = s, u = s; *t; ++t, ++u) {
+ if((*t == '%') && t[1] && t[2]) {
+ *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) +
+ (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0'));
+ t += 2;
+ }
+ else
+ if(u != t)
+ *u = *t;
+ if (*u == '\\') /* normalize */
+ *u = '/';
+ }
+ *u = *t;
+}
+#endif /* XP_WIN32 */
+
+/* -------------------------- util_uri_unescape --------------------------- */
+
+NSAPI_PUBLIC void util_uri_unescape(char *s)
+{
+ char *t, *u;
+
+ for(t = s, u = s; *t; ++t, ++u) {
+ if((*t == '%') && t[1] && t[2]) {
+ *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) +
+ (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0'));
+ t += 2;
+ }
+ else
+ if(u != t)
+ *u = *t;
+ }
+ *u = *t;
+}
+
+
+/* --------------------------- util_uri_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_uri_escape(char *od, char *s)
+{
+ char *d;
+
+ if(!od)
+ od = (char *) MALLOC((strlen(s)*3) + 1);
+ d = od;
+
+ while(*s) {
+ if(strchr("% ?#:+&*\"<>\r\n", *s)) {
+ sprintf(d, "%%%2x", *s);
+ ++s; d += 3;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return od;
+}
+
+
+/* --------------------------- util_url_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_url_escape(char *od, char *s)
+{
+ char *d;
+
+ if(!od)
+ od = (char *) MALLOC((strlen(s)*3) + 1);
+ d = od;
+
+ while(*s) {
+ if(strchr("% +*\"<>\r\n", *s)) {
+ sprintf(d, "%%%.2x", *s);
+ ++s; d += 3;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return od;
+}
+
+
+/* ------------------------- util_mime_separator -------------------------- */
+
+
+NSAPI_PUBLIC int util_mime_separator(char *sep)
+{
+ srand(time(NULL));
+ return util_sprintf(sep, "%c%c--%d%d%d", CR, LF, rand(), rand(), rand());
+}
+
+
+/* ------------------------------ util_itoa ------------------------------- */
+
+
+/*
+ * Assumption: Reversing the digits will be faster in the general case
+ * than doing a log10 or some nasty trick to find the # of digits.
+ */
+
+NSAPI_PUBLIC int util_itoa(int i, char *a)
+{
+ register int x, y, p;
+ register char c;
+ int negative;
+
+ negative = 0;
+ if(i < 0) {
+ *a++ = '-';
+ negative = 1;
+ i = -i;
+ }
+ p = 0;
+ while(i > 9) {
+ a[p++] = (i%10) + '0';
+ i /= 10;
+ }
+ a[p++] = i + '0';
+
+ if(p > 1) {
+ for(x = 0, y = p - 1; x < y; ++x, --y) {
+ c = a[x];
+ a[x] = a[y];
+ a[y] = c;
+ }
+ }
+ a[p] = '\0';
+ return p + negative;
+}
+
+
+/* ----------------------------- util_sprintf ----------------------------- */
+
+
+#include "prprf.h"
+
+/*
+ XXXrobm the NSPR interfaces don't allow me to just pass in a buffer
+ without a size
+ */
+#define UTIL_PRF_MAXSIZE 1048576
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt,
+ va_list args)
+{
+ return PR_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return PR_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args)
+{
+ return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
+}
+
+/* ---------------------------- util_sh_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_sh_escape(char *s)
+{
+ char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */
+ register char *t, *u;
+
+ for(t = s, u = ns; *t; ++t, ++u) {
+ if(strchr("&;`'\"|*?~<>^()[]{}$\\ #!", *t))
+ *u++ = '\\';
+ *u = *t;
+ }
+ *u = '\0';
+ return ns;
+}
+
+/* --------------------------- util_strcasecmp ---------------------------- */
+
+
+#ifdef NEED_STRCASECMP
+/* These are stolen from mcom/lib/xp */
+NSAPI_PUBLIC
+int util_strcasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two)
+{
+ CASECMPARG_T char *pA;
+ CASECMPARG_T char *pB;
+
+ for(pA=one, pB=two; *pA && *pB; pA++, pB++)
+ {
+ int tmp = tolower(*pA) - tolower(*pB);
+ if (tmp)
+ return tmp;
+ }
+ if (*pA)
+ return 1;
+ if (*pB)
+ return -1;
+ return 0;
+}
+#endif /* NEED_STRCASECMP */
+
+#ifdef NEED_STRNCASECMP
+NSAPI_PUBLIC
+int util_strncasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two, int n)
+{
+ CASECMPARG_T char *pA;
+ CASECMPARG_T char *pB;
+
+ for(pA=one, pB=two;; pA++, pB++)
+ {
+ int tmp;
+ if (pA == one+n)
+ return 0;
+ if (!(*pA && *pB))
+ return *pA - *pB;
+ tmp = tolower(*pA) - tolower(*pB);
+ if (tmp)
+ return tmp;
+ }
+}
+#endif /* NEED_STRNCASECMP */
+
+#ifdef XP_WIN32
+
+
+/* util_delete_directory()
+ * This routine deletes all the files in a directory. If delete_directory is
+ * TRUE it will also delete the directory itself.
+ */
+VOID
+util_delete_directory(char *FileName, BOOL delete_directory)
+{
+ HANDLE firstFile;
+ WIN32_FIND_DATA findData;
+ char *TmpFile, *NewFile;
+
+ if (FileName == NULL)
+ return;
+
+ TmpFile = (char *)MALLOC(strlen(FileName) + 5);
+ sprintf(TmpFile, "%s\\*.*", FileName);
+ firstFile = FindFirstFile(TmpFile, &findData);
+ FREE(TmpFile);
+
+ if (firstFile == INVALID_HANDLE_VALUE)
+ return;
+
+ if(strcmp(findData.cFileName, ".") &&
+ strcmp(findData.cFileName, "..")) {
+ NewFile = (char *)MALLOC(strlen(FileName) + 1 +
+ strlen(findData.cFileName) + 1);
+ sprintf(NewFile, "%s\\%s",FileName, findData.cFileName);
+ DeleteFile(NewFile);
+ FREE(NewFile);
+ }
+ while (TRUE) {
+ if(!(FindNextFile(firstFile, &findData))) {
+ if (GetLastError() != ERROR_NO_MORE_FILES) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_), FileName, GetLastError());
+ } else {
+ FindClose(firstFile);
+ if (delete_directory)
+ if(!RemoveDirectory(FileName)) {
+ ereport(LOG_WARN,
+ XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_1),
+ FileName, GetLastError());
+ }
+ return;
+ }
+ } else {
+ if(strcmp(findData.cFileName, ".") &&
+ strcmp(findData.cFileName, "..")) {
+ NewFile = (char *)MALLOC(strlen(FileName) + 5 +
+ strlen(findData.cFileName) + 1);
+ sprintf(NewFile,"%s\\%s", FileName, findData.cFileName);
+ DeleteFile(NewFile);
+ FREE(NewFile);
+ }
+ }
+ }
+}
+#endif
+
+/* ------------------------------ util_strftime --------------------------- */
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strftime.c 5.11 (Berkeley) 2/24/91";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#endif
+
+static char *afmt[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+};
+static char *Afmt[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+ "Saturday",
+};
+
+static char *bfmt[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec",
+};
+static char *Bfmt[] = {
+ "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December",
+};
+
+#define TM_YEAR_BASE 1900
+
+static void _util_strftime_conv(char *, int, int, char);
+
+#define _util_strftime_add(str) for (;(*pt = *str++); pt++);
+#define _util_strftime_copy(str, len) memcpy(pt, str, len); pt += len;
+#define _util_strftime_fmt util_strftime
+
+/* util_strftime()
+ * This is an optimized version of strftime for speed. Avoids the thread
+ * unsafeness of BSD strftime calls.
+ */
+int
+util_strftime(char *pt, const char *format, const struct tm *t)
+{
+ char *start = pt;
+ char *scrap;
+
+ for (; *format; ++format) {
+ if (*format == '%')
+ switch(*++format) {
+ case 'a': /* abbreviated weekday name */
+ *pt++ = afmt[t->tm_wday][0];
+ *pt++ = afmt[t->tm_wday][1];
+ *pt++ = afmt[t->tm_wday][2];
+ continue;
+ case 'd': /* day of month */
+ _util_strftime_conv(pt, t->tm_mday, 2, '0');
+ pt += 2;
+ continue;
+ case 'S':
+ _util_strftime_conv(pt, t->tm_sec, 2, '0');
+ pt += 2;
+ continue;
+ case 'M':
+ _util_strftime_conv(pt, t->tm_min, 2, '0');
+ pt += 2;
+ continue;
+ case 'H':
+ _util_strftime_conv(pt, t->tm_hour, 2, '0');
+ pt += 2;
+ continue;
+ case 'Y':
+ if (t->tm_year < 100) {
+ *pt++ = '1';
+ *pt++ = '9';
+ _util_strftime_conv(pt, t->tm_year, 2, '0');
+ } else {
+ /* will fail after 2100; but who cares? */
+ *pt++ = '2';
+ *pt++ = '0';
+ _util_strftime_conv(pt, t->tm_year-100, 2, '0');
+ }
+ pt += 2;
+ continue;
+ case 'b': /* abbreviated month name */
+ case 'h':
+ *pt++ = bfmt[t->tm_mon][0];
+ *pt++ = bfmt[t->tm_mon][1];
+ *pt++ = bfmt[t->tm_mon][2];
+ continue;
+ case 'T':
+ case 'X':
+ pt += _util_strftime_fmt(pt, "%H:%M:%S", t);
+ continue;
+ case '\0':
+ --format;
+ break;
+ case 'A':
+ if (t->tm_wday < 0 || t->tm_wday > 6)
+ return(0);
+ scrap = Afmt[t->tm_wday];
+ _util_strftime_add(scrap);
+ continue;
+ case 'B':
+ if (t->tm_mon < 0 || t->tm_mon > 11)
+ return(0);
+ scrap = Bfmt[t->tm_mon];
+ _util_strftime_add(scrap);
+ continue;
+ case 'C':
+ pt += _util_strftime_fmt(pt, "%a %b %e %H:%M:%S %Y", t);
+ continue;
+ case 'c':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y %H:%M:%S", t);
+ continue;
+ case 'D':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
+ continue;
+ case 'e':
+ _util_strftime_conv(pt, t->tm_mday, 2, ' ');
+ pt += 2;
+ continue;
+ case 'I':
+ _util_strftime_conv(pt, t->tm_hour % 12 ?
+ t->tm_hour % 12 : 12, 2, '0');
+ pt += 2;
+ continue;
+ case 'j':
+ _util_strftime_conv(pt, t->tm_yday + 1, 3, '0');
+ pt += 3;
+ continue;
+ case 'k':
+ _util_strftime_conv(pt, t->tm_hour, 2, ' ');
+ pt += 2;
+ continue;
+ case 'l':
+ _util_strftime_conv(pt, t->tm_hour % 12 ?
+ t->tm_hour % 12 : 12, 2, ' ');
+ pt += 2;
+ continue;
+ case 'm':
+ _util_strftime_conv(pt, t->tm_mon + 1, 2, '0');
+ pt += 2;
+ continue;
+ case 'n':
+ *pt = '\n';
+ pt++;
+ continue;
+ case 'p':
+ if (t->tm_hour >= 12) {
+ *pt = 'P';
+ pt++;
+ } else {
+ *pt = 'A';
+ pt++;
+ }
+ *pt = 'M';
+ pt++;
+ continue;
+ case 'R':
+ pt += _util_strftime_fmt(pt, "%H:%M", t);
+ continue;
+ case 'r':
+ pt += _util_strftime_fmt(pt, "%I:%M:%S %p", t);
+ continue;
+ case 't':
+ *pt = '\t';
+ pt++;
+ continue;
+ case 'U':
+ _util_strftime_conv(pt, (t->tm_yday + 7 - t->tm_wday) / 7,
+ 2, '0');
+ pt += 2;
+ continue;
+ case 'W':
+ _util_strftime_conv(pt, (t->tm_yday + 7 -
+ (t->tm_wday ? (t->tm_wday - 1) : 6))
+ / 7, 2, '0');
+ pt += 2;
+ continue;
+ case 'w':
+ _util_strftime_conv(pt, t->tm_wday, 1, '0');
+ pt += 1;
+ continue;
+ case 'x':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
+ continue;
+ case 'y':
+ _util_strftime_conv(pt, (t->tm_year + TM_YEAR_BASE)
+ % 100, 2, '0');
+ pt += 2;
+ continue;
+ case '%':
+ /*
+ * X311J/88-090 (4.12.3.5): if conversion char is
+ * undefined, behavior is undefined. Print out the
+ * character itself as printf(3) does.
+ */
+ default:
+ break;
+ }
+ *pt = *format;
+ pt++;
+ }
+
+ start[pt-start] = '\0';
+
+ return pt - start;
+}
+
+static void
+_util_strftime_conv(char *pt, int n, int digits, char pad)
+{
+ static char buf[10];
+ register char *p;
+
+ if (n >= 100) {
+ p = buf + sizeof(buf)-2;
+ for (; n > 0 && p > buf; n /= 10, --digits)
+ *p-- = n % 10 + '0';
+ while (p > buf && digits-- > 0)
+ *p-- = pad;
+ p++;
+ _util_strftime_add(p);
+ } else {
+ int tens;
+ int ones = n;
+
+ tens = 0;
+ if ( ones >= 10 ) {
+ while ( ones >= 10 ) {
+ tens++;
+ ones = ones - 10;
+ }
+ *pt++ = '0'+tens;
+ digits--;
+ }
+ else
+ *pt++ = '0';
+ *pt++ = '0'+ones;
+ digits--;
+ while(digits--)
+ *pt++ = pad;
+ }
+ return;
+}
+
+
+#ifdef XP_UNIX
+/*
+ * Local Thread Safe version of waitpid. This prevents the process
+ * from blocking in the system call.
+ */
+NSAPI_PUBLIC pid_t
+util_waitpid(pid_t pid, int *statptr, int options)
+{
+ pid_t rv;
+
+ for(rv = 0; !rv; PR_Sleep(500)) {
+ rv = waitpid(pid, statptr, options | WNOHANG);
+ if (rv == -1) {
+ if (errno == EINTR)
+ rv = 0; /* sleep and try again */
+ else
+ ereport(LOG_WARN, "waitpid failed for pid %d:%s", pid, system_errmsg());
+ }
+ }
+ return rv;
+}
+#endif
+
+/*
+ * Various reentrant routines by mikep. See util.h and systems.h
+ */
+
+/*
+ * These are only necessary if we turn on interrupts in NSPR
+ */
+#ifdef NEED_RELOCKS
+#include "crit.h"
+#define RE_LOCK(name) \
+ static CRITICAL name##_crit = 0; \
+ if (name##_crit == 0) name##_crit = crit_init(); \
+ crit_enter(name##_crit)
+
+#define RE_UNLOCK(name) crit_exit(name##_crit)
+
+#else
+#define RE_LOCK(name) /* nada */
+#define RE_UNLOCK(name) /* nil */
+#endif
+
+
+NSAPI_PUBLIC char *
+util_strtok(register char *s,
+ register const char *delim,
+ register char **lasts)
+{
+#ifdef HAVE_STRTOK_R
+ return strtok_r(s, delim, lasts);
+#else
+ /*
+ * THIS IS THE THREAD SAFE VERSION OF strtok captured from
+ * public NetBSD. Note that no locks are needed
+ */
+ register char *spanp;
+ register int c, sc;
+ char *tok;
+
+ if (s == NULL && (s = *lasts) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim),
+ * sort of).
+ */
+
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *lasts = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim),
+ * sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *lasts = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+#endif /* no strtok_r */
+}
+
+#ifndef XP_WIN32
+NSAPI_PUBLIC struct passwd *
+util_getpwnam(const char *name, struct passwd *result, char *buffer,
+ int buflen)
+{
+#ifdef HAVE_PW_R
+
+#ifdef AIX
+#if OSVERSION >= 4320
+ return ((int)getpwnam_r(name, result, buffer, buflen, 0) == 0 ? result : NULL);
+#else
+ return ((int)getpwnam_r(name, result, buffer, buflen) == 0 ? result : NULL);
+#endif
+#else
+ return getpwnam_r(name, result, buffer, buflen);
+#endif /* AIX */
+
+#else
+ char *lastp;
+ struct passwd *r;
+ RE_LOCK(pw);
+ r = getpwnam(name);
+ if (!r)
+ return r;
+
+ result->pw_gid = r->pw_gid;
+ result->pw_uid = r->pw_uid;
+ /* Hope this buffer is long enough */
+ if (buffer)
+ util_snprintf(buffer, buflen, "%s:%s:%d:%d:%s:%s:%s", r->pw_name, r->pw_passwd,
+ r->pw_uid, r->pw_gid, r->pw_gecos, r->pw_dir, r->pw_shell);
+ RE_UNLOCK(pw);
+
+ result->pw_name = util_strtok(buffer, ":", &lastp);
+ result->pw_passwd = util_strtok(NULL, ":", &lastp);
+ (void) util_strtok(NULL, ":", &lastp);
+ (void) util_strtok(NULL, ":", &lastp);
+ result->pw_gecos = util_strtok(NULL, ":", &lastp);
+ result->pw_dir = util_strtok(NULL, ":", &lastp);
+ result->pw_shell = util_strtok(NULL, ":", &lastp);
+ return result;
+#endif
+}
+#endif
+
+NSAPI_PUBLIC struct tm *
+util_localtime(const time_t *clock, struct tm *res)
+{
+#ifdef HAVE_TIME_R
+ return localtime_r(clock, res);
+#else
+ struct tm *rv;
+ time_t zero = 0x7fffffff;
+
+ RE_LOCK(localtime);
+ RE_UNLOCK(localtime);
+ rv = localtime(clock);
+ if (!rv)
+ rv = localtime(&zero);
+ if (rv)
+ *res = *rv;
+ else
+ return NULL;
+ return res;
+#endif
+}
+
+
+NSAPI_PUBLIC char *
+util_ctime(const time_t *clock, char *buf, int buflen)
+{
+/*
+ * From cgi-src/restore.c refering to XP_WIN32:
+ * MLM - gross, but it works, better now FLC
+ */
+#if !defined(HAVE_TIME_R) || defined(XP_WIN32)
+ RE_LOCK(ctime);
+ strncpy(buf, ctime(clock), buflen);
+ buf[buflen - 1] = '\0';
+ RE_UNLOCK(ctime);
+ return buf;
+#elif HAVE_TIME_R == 2
+ return ctime_r(clock, buf);
+#else /* HAVE_TIME_R == 3 */
+ return ctime_r(clock, buf, buflen);
+#endif
+}
+
+NSAPI_PUBLIC struct tm *
+util_gmtime(const time_t *clock, struct tm *res)
+{
+#ifdef HAVE_TIME_R
+ return gmtime_r(clock, res);
+#else
+ struct tm *rv;
+ time_t zero = 0x7fffffff;
+
+ RE_LOCK(gmtime);
+ rv = gmtime(clock);
+ RE_UNLOCK(gmtime);
+ if (!rv)
+ rv = gmtime(&zero);
+ if (rv)
+ *res = *rv;
+ else
+ return NULL;
+
+ return res;
+#endif
+}
+
+NSAPI_PUBLIC char *
+util_asctime(const struct tm *tm, char *buf, int buflen)
+{
+#if HAVE_TIME_R == 2
+ return asctime_r(tm, buf);
+#elif HAVE_TIME_R == 3
+ return asctime_r(tm, buf, buflen);
+#else
+ RE_LOCK(asctime);
+ strncpy(buf, asctime(tm), buflen);
+ buf[buflen - 1] = '\0';
+ RE_UNLOCK(asctime);
+ return buf;
+#endif
+}
+
+NSAPI_PUBLIC char *
+util_strerror(int errnum, char *msg, int buflen)
+{
+#ifdef HAVE_STRERROR_R
+ /* More IBM real-genius */
+ return ((int)strerror_r(errnum, msg, buflen) > 0) ? msg : NULL;
+#else
+ /* RE_LOCK(strerror); I don't think this is worth the trouble */
+ (void)strncpy(msg, strerror(errnum), buflen);
+ msg[buflen - 1] = '\0';
+ return msg;
+ /* RE_UNLOCK(strerror); */
+#endif
+}
+
+
+
+/* ------------------------------- OLD CODE ------------------------------- */
+
+
+#if 0
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register char *fmt,
+ va_list args)
+{
+ register int pos = 0, max = (n > 2 ? n-2 : -1), boundson;
+ register char c, *t;
+
+ if((max == -1) && (n != -1))
+ goto punt;
+
+ boundson = (n != -1);
+ while(*fmt) {
+ if(boundson && (pos > max))
+ break;
+ c = *fmt++;
+ switch(c) {
+ case '%':
+ switch(*fmt++) {
+ case 'd':
+ if(boundson && ((pos + 10) > max))
+ goto punt;
+ pos += util_itoa(va_arg(args, int), &s[pos]);
+ break;
+ case 's':
+ t = va_arg(args, char *);
+ while(*t) {
+ s[pos++] = *t++;
+ if(boundson && (pos > max))
+ goto punt;
+ }
+ break;
+ case 'c':
+ s[pos++] = (char) va_arg(args, int);
+ break;
+ case '%':
+ s[pos++] = '%';
+ break;
+ }
+ break;
+ case '\\':
+ if( (s[pos++] = *fmt) )
+ ++fmt;
+ break;
+ default:
+ s[pos++] = c;
+ }
+ }
+ punt:
+ s[pos] = '\0';
+
+ va_end(args);
+ return pos;
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register char *fmt, va_list args)
+{
+ return util_vsnprintf(s, -1, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, -1, fmt, args);
+}
+#endif