summaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--misc/netware/apr.xdcbin0 -> 128 bytes
-rw-r--r--misc/netware/aprlib.def3
-rw-r--r--misc/netware/charset.c34
-rw-r--r--misc/netware/libprews.c186
-rw-r--r--misc/netware/rand.c70
-rw-r--r--misc/netware/start.c203
-rw-r--r--misc/unix/charset.c83
-rw-r--r--misc/unix/env.c88
-rw-r--r--misc/unix/errorcodes.c443
-rw-r--r--misc/unix/getopt.c309
-rw-r--r--misc/unix/otherchild.c221
-rw-r--r--misc/unix/rand.c302
-rw-r--r--misc/unix/randbyte_os2.inc123
-rw-r--r--misc/unix/start.c89
-rw-r--r--misc/unix/version.c35
-rw-r--r--misc/win32/apr_app.c104
-rw-r--r--misc/win32/charset.c55
-rw-r--r--misc/win32/env.c192
-rw-r--r--misc/win32/internal.c101
-rw-r--r--misc/win32/misc.c266
-rw-r--r--misc/win32/rand.c69
-rw-r--r--misc/win32/start.c232
-rw-r--r--misc/win32/utf8.c259
23 files changed, 3467 insertions, 0 deletions
diff --git a/misc/netware/apr.xdc b/misc/netware/apr.xdc
new file mode 100644
index 0000000..12a7f6b
--- /dev/null
+++ b/misc/netware/apr.xdc
Binary files differ
diff --git a/misc/netware/aprlib.def b/misc/netware/aprlib.def
new file mode 100644
index 0000000..0a2a01e
--- /dev/null
+++ b/misc/netware/aprlib.def
@@ -0,0 +1,3 @@
+MODULE LIBC.NLM
+MODULE WS2_32.NLM
+EXPORT @aprlib.imp
diff --git a/misc/netware/charset.c b/misc/netware/charset.c
new file mode 100644
index 0000000..b79add1
--- /dev/null
+++ b/misc/netware/charset.c
@@ -0,0 +1,34 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_portable.h"
+
+/* static struct utsname sysinfo; */
+
+/* XXX This needs to be fixed to produce the correct system language */
+
+APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool)
+{
+ return apr_pstrdup(pool, "CP1252");
+}
+
+
+APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool)
+{
+ return apr_os_default_encoding(pool);
+}
diff --git a/misc/netware/libprews.c b/misc/netware/libprews.c
new file mode 100644
index 0000000..6e37ccf
--- /dev/null
+++ b/misc/netware/libprews.c
@@ -0,0 +1,186 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <netware.h>
+#include <library.h>
+#include <nks/synch.h>
+
+#include "apr_pools.h"
+#include "apr_private.h"
+#include "apr_arch_internal_time.h"
+
+
+/* library-private data...*/
+int gLibId = -1;
+void *gLibHandle = (void *) NULL;
+NXMutex_t *gLibLock = (NXMutex_t *) NULL;
+
+/* internal library function prototypes...*/
+int DisposeLibraryData(void *);
+
+int _NonAppStart
+(
+ void *NLMHandle,
+ void *errorScreen,
+ const char *cmdLine,
+ const char *loadDirPath,
+ size_t uninitializedDataLength,
+ void *NLMFileHandle,
+ int (*readRoutineP)( int conn, void *fileHandle, size_t offset,
+ size_t nbytes, size_t *bytesRead, void *buffer ),
+ size_t customDataOffset,
+ size_t customDataSize,
+ int messageCount,
+ const char **messages
+)
+{
+#ifdef USE_WINSOCK
+ WSADATA wsaData;
+#endif
+ apr_status_t status;
+
+ NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
+
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+
+ gLibId = register_library(DisposeLibraryData);
+
+ if (gLibId < -1)
+ {
+ OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
+ return -1;
+ }
+
+ gLibHandle = NLMHandle;
+
+ gLibLock = NXMutexAlloc(0, 0, &liblock);
+
+ if (!gLibLock)
+ {
+ OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
+ return -1;
+ }
+
+ apr_netware_setup_time();
+
+ if ((status = apr_pool_initialize()) != APR_SUCCESS)
+ return status;
+
+#ifdef USE_WINSOCK
+ return WSAStartup((WORD) MAKEWORD(2, 0), &wsaData);
+#else
+ return 0;
+#endif
+}
+
+void _NonAppStop( void )
+{
+ apr_pool_terminate();
+
+#ifdef USE_WINSOCK
+ WSACleanup();
+#endif
+
+ unregister_library(gLibId);
+ NXMutexFree(gLibLock);
+}
+
+int _NonAppCheckUnload( void )
+{
+ return 0;
+}
+
+int register_NLM(void *NLMHandle)
+{
+ APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId);
+
+ NXLock(gLibLock);
+ if (!app_data) {
+ app_data = (APP_DATA*)library_malloc(gLibHandle, sizeof(APP_DATA));
+
+ if (app_data) {
+ memset (app_data, 0, sizeof(APP_DATA));
+ set_app_data(gLibId, app_data);
+ app_data->gs_nlmhandle = NLMHandle;
+ }
+ }
+
+ if (app_data && (!app_data->initialized)) {
+ app_data->initialized = 1;
+ NXUnlock(gLibLock);
+ return 0;
+ }
+
+ NXUnlock(gLibLock);
+ return 1;
+}
+
+int unregister_NLM(void *NLMHandle)
+{
+ APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId);
+
+ NXLock(gLibLock);
+ if (app_data) {
+ app_data->initialized = 0;
+ NXUnlock(gLibLock);
+ return 0;
+ }
+ NXUnlock(gLibLock);
+ return 1;
+}
+
+int DisposeLibraryData(void *data)
+{
+ if (data)
+ {
+ library_free(data);
+ }
+
+ return 0;
+}
+
+int setGlobalPool(void *data)
+{
+ APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId);
+
+ NXLock(gLibLock);
+
+ if (app_data && !app_data->gPool) {
+ app_data->gPool = data;
+ }
+
+ NXUnlock(gLibLock);
+ return 1;
+}
+
+void* getGlobalPool()
+{
+ APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId);
+
+ if (app_data) {
+ return app_data->gPool;
+ }
+
+ return NULL;
+}
+
diff --git a/misc/netware/rand.c b/misc/netware/rand.c
new file mode 100644
index 0000000..a2baae7
--- /dev/null
+++ b/misc/netware/rand.c
@@ -0,0 +1,70 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define APR_WANT_MEMFUNC
+#include "apr_want.h"
+#include "apr_general.h"
+#include "apr_private.h"
+
+#if APR_HAS_RANDOM
+
+#include <nks/plat.h>
+
+static int NXSeedRandomInternal( size_t width, void *seed )
+{
+ static int init = 0;
+ int *s = (int *) seed;
+ union { int x; char y[4]; } u;
+
+ if (!init) {
+ srand(NXGetSystemTick());
+ init = 1;
+ }
+
+ if (width > 3)
+ {
+ do
+ {
+ *s++ = rand();
+ }
+ while ((width -= 4) > 3);
+ }
+
+ if (width > 0)
+ {
+ char *p = (char *) s;
+
+ u.x = rand();
+
+ while (width > 0)
+ *p++ = u.y[width--];
+ }
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
+ apr_size_t length)
+{
+ if (NXSeedRandom(length, buf) != 0) {
+ return NXSeedRandomInternal (length, buf);
+ }
+ return APR_SUCCESS;
+}
+
+
+
+#endif /* APR_HAS_RANDOM */
diff --git a/misc/netware/start.c b/misc/netware/start.c
new file mode 100644
index 0000000..76817d9
--- /dev/null
+++ b/misc/netware/start.c
@@ -0,0 +1,203 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_signal.h"
+
+#include "apr_arch_misc.h" /* for WSAHighByte / WSALowByte */
+#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */
+#include "apr_arch_internal_time.h"
+#include "apr_ldap.h" /* for apr_ldap_rebind_init() */
+
+#ifdef USE_WINSOCK
+/* Prototypes missing from older NDKs */
+int WSAStartupRTags(WORD wVersionRequested,
+ LPWSADATA lpWSAData,
+ rtag_t WSAStartupRTag,
+ rtag_t WSPSKTRTag,
+ rtag_t lookUpServiceBeginRTag,
+ rtag_t WSAEventRTag,
+ rtag_t WSPCPRTag);
+
+int WSACleanupRTag(rtag_t rTag);
+
+/*
+** Resource tag signatures for using NetWare WinSock 2. These will no longer
+** be needed by anyone once the new WSAStartupWithNlmHandle() is available
+** since WinSock will make the calls to AllocateResourceTag().
+*/
+#define WS_LOAD_ENTRY_SIGNATURE (*(unsigned long *) "WLDE")
+#define WS_SKT_SIGNATURE (*(unsigned long *) "WSKT")
+#define WS_LOOKUP_SERVICE_SIGNATURE (*(unsigned long *) "WLUP")
+#define WS_WSAEVENT_SIGNATURE (*(unsigned long *) "WEVT")
+#define WS_CPORT_SIGNATURE (*(unsigned long *) "WCPT")
+
+
+int (*WSAStartupWithNLMHandle)( WORD version, LPWSADATA data, void *handle ) = NULL;
+int (*WSACleanupWithNLMHandle)( void *handle ) = NULL;
+
+static int wsa_startup_with_handle (WORD wVersionRequested, LPWSADATA data, void *handle)
+{
+ APP_DATA *app_data;
+
+ if (!(app_data = (APP_DATA*) get_app_data(gLibId)))
+ return APR_EGENERAL;
+
+ app_data->gs_startup_rtag = AllocateResourceTag(handle, "WinSock Start-up", WS_LOAD_ENTRY_SIGNATURE);
+ app_data->gs_socket_rtag = AllocateResourceTag(handle, "WinSock socket()", WS_SKT_SIGNATURE);
+ app_data->gs_lookup_rtag = AllocateResourceTag(handle, "WinSock Look-up", WS_LOOKUP_SERVICE_SIGNATURE);
+ app_data->gs_event_rtag = AllocateResourceTag(handle, "WinSock Event", WS_WSAEVENT_SIGNATURE);
+ app_data->gs_pcp_rtag = AllocateResourceTag(handle, "WinSock C-Port", WS_CPORT_SIGNATURE);
+
+ return WSAStartupRTags(wVersionRequested, data,
+ app_data->gs_startup_rtag,
+ app_data->gs_socket_rtag,
+ app_data->gs_lookup_rtag,
+ app_data->gs_event_rtag,
+ app_data->gs_pcp_rtag);
+}
+
+static int wsa_cleanup_with_handle (void *handle)
+{
+ APP_DATA *app_data;
+
+ if (!(app_data = (APP_DATA*) get_app_data(gLibId)))
+ return APR_EGENERAL;
+
+ return WSACleanupRTag(app_data->gs_startup_rtag);
+}
+
+static int UnregisterAppWithWinSock (void *nlm_handle)
+{
+ if (!WSACleanupWithNLMHandle)
+ {
+ if (!(WSACleanupWithNLMHandle = ImportPublicObject(gLibHandle, "WSACleanupWithNLMHandle")))
+ WSACleanupWithNLMHandle = wsa_cleanup_with_handle;
+ }
+
+ return (*WSACleanupWithNLMHandle)(nlm_handle);
+}
+
+static int RegisterAppWithWinSock (void *nlm_handle)
+{
+ int err;
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(WSAHighByte, WSALowByte);
+
+ if (!WSAStartupWithNLMHandle)
+ {
+ if (!(WSAStartupWithNLMHandle = ImportPublicObject(gLibHandle, "WSAStartupWithNLMHandle")))
+ WSAStartupWithNLMHandle = wsa_startup_with_handle;
+ }
+
+ err = (*WSAStartupWithNLMHandle)(wVersionRequested, &wsaData, nlm_handle);
+
+ if (LOBYTE(wsaData.wVersion) != WSAHighByte ||
+ HIBYTE(wsaData.wVersion) != WSALowByte) {
+
+ UnregisterAppWithWinSock (nlm_handle);
+ return APR_EEXIST;
+ }
+
+ return err;
+}
+#endif
+
+
+
+APR_DECLARE(apr_status_t) apr_app_initialize(int *argc,
+ const char * const * *argv,
+ const char * const * *env)
+{
+ /* An absolute noop. At present, only Win32 requires this stub, but it's
+ * required in order to move command arguments passed through the service
+ * control manager into the process, and it's required to fix the char*
+ * data passed in from win32 unicode into utf-8, win32's apr internal fmt.
+ */
+ return apr_initialize();
+}
+
+APR_DECLARE(apr_status_t) apr_initialize(void)
+{
+ apr_pool_t *pool;
+ void *nlmhandle = getnlmhandle();
+
+ /* Register the NLM as using APR. If it is already
+ registered then just return. */
+ if (register_NLM(nlmhandle) != 0) {
+ return APR_SUCCESS;
+ }
+
+ /* apr_pool_initialize() is being called from the library
+ startup code since all of the memory resources belong
+ to the library rather than the application. */
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return APR_ENOPOOL;
+ }
+
+ apr_pool_tag(pool, "apr_initilialize");
+
+#ifdef USE_WINSOCK
+ {
+ int err;
+ if ((err = RegisterAppWithWinSock (nlmhandle))) {
+ return err;
+ }
+ }
+#endif
+
+ apr_signal_init(pool);
+#if APR_HAS_LDAP
+ apr_ldap_rebind_init(pool);
+#endif
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE_NONSTD(void) apr_terminate(void)
+{
+ APP_DATA *app_data;
+
+ /* Get our instance data for shutting down. */
+ if (!(app_data = (APP_DATA*) get_app_data(gLibId)))
+ return;
+
+ /* Unregister the NLM. If it is not registered
+ then just return. */
+ if (unregister_NLM(app_data->gs_nlmhandle) != 0) {
+ return;
+ }
+
+ /* apr_pool_terminate() is being called from the
+ library shutdown code since the memory resources
+ belong to the library rather than the application */
+
+ /* Just clean up the memory for the app that is going
+ away. */
+ netware_pool_proc_cleanup ();
+
+#ifdef USE_WINSOCK
+ UnregisterAppWithWinSock (app_data->gs_nlmhandle);
+#endif
+}
+
+APR_DECLARE(void) apr_terminate2(void)
+{
+ apr_terminate();
+}
diff --git a/misc/unix/charset.c b/misc/unix/charset.c
new file mode 100644
index 0000000..a16310c
--- /dev/null
+++ b/misc/unix/charset.c
@@ -0,0 +1,83 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_private.h"
+#include "apr_strings.h"
+#include "apr_portable.h"
+
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+/*
+ * simple heuristic to determine codepage of source code so that
+ * literal strings (e.g., "GET /\r\n") in source code can be translated
+ * properly
+ *
+ * If appropriate, a symbol can be set at configure time to determine
+ * this. On EBCDIC platforms, it will be important how the code was
+ * unpacked.
+ */
+
+APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool)
+{
+#ifdef __MVS__
+# ifdef __CODESET__
+ return __CODESET__;
+# else
+ return "IBM-1047";
+# endif
+#endif
+
+ if ('}' == 0xD0) {
+ return "IBM-1047";
+ }
+
+ if ('{' == 0xFB) {
+ return "EDF04";
+ }
+
+ if ('A' == 0xC1) {
+ return "EBCDIC"; /* not useful */
+ }
+
+ if ('A' == 0x41) {
+ return "ISO-8859-1"; /* not necessarily true */
+ }
+
+ return "unknown";
+}
+
+
+APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool)
+{
+#if defined(HAVE_NL_LANGINFO) && defined(CODESET)
+ const char *charset;
+
+ charset = nl_langinfo(CODESET);
+ if (charset && *charset) {
+#ifdef _OSD_POSIX /* Bug workaround - delete as soon as fixed in OSD_POSIX */
+ /* Some versions of OSD_POSIX return nl_langinfo(CODESET)="^[nN]" */
+ /* Ignore the bogus information and use apr_os_default_encoding() */
+ if (charset[0] != '^')
+#endif
+ return apr_pstrdup(pool, charset);
+ }
+#endif
+
+ return apr_os_default_encoding(pool);
+}
diff --git a/misc/unix/env.c b/misc/unix/env.c
new file mode 100644
index 0000000..b41f8f1
--- /dev/null
+++ b/misc/unix/env.c
@@ -0,0 +1,88 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr.h"
+#include "apr_private.h"
+#include "apr_env.h"
+#include "apr_strings.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+APR_DECLARE(apr_status_t) apr_env_get(char **value,
+ const char *envvar,
+ apr_pool_t *pool)
+{
+#ifdef HAVE_GETENV
+
+ char *val = getenv(envvar);
+ if (!val)
+ return APR_ENOENT;
+ *value = val;
+ return APR_SUCCESS;
+
+#else
+ return APR_ENOTIMPL;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_set(const char *envvar,
+ const char *value,
+ apr_pool_t *pool)
+{
+#if defined(HAVE_SETENV)
+
+ if (0 > setenv(envvar, value, 1))
+ return APR_ENOMEM;
+ return APR_SUCCESS;
+
+#elif defined(HAVE_PUTENV)
+
+ if (0 > putenv(apr_pstrcat(pool, envvar, "=", value, NULL)))
+ return APR_ENOMEM;
+ return APR_SUCCESS;
+
+#else
+ return APR_ENOTIMPL;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool)
+{
+#ifdef HAVE_UNSETENV
+
+ unsetenv(envvar);
+ return APR_SUCCESS;
+
+#else
+ /* hint: some platforms allow envvars to be unset via
+ * putenv("varname")... that isn't Single Unix spec,
+ * but if your platform doesn't have unsetenv() it is
+ * worth investigating and potentially adding a
+ * configure check to decide when to use that form of
+ * putenv() here
+ */
+ return APR_ENOTIMPL;
+#endif
+}
diff --git a/misc/unix/errorcodes.c b/misc/unix/errorcodes.c
new file mode 100644
index 0000000..60ea2f7
--- /dev/null
+++ b/misc/unix/errorcodes.c
@@ -0,0 +1,443 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_arch_misc.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_dso.h"
+
+#if APR_HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+/*
+ * stuffbuffer - like apr_cpystrn() but returns the address of the
+ * dest buffer instead of the address of the terminating '\0'
+ */
+static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s)
+{
+ apr_cpystrn(buf,s,bufsize);
+ return buf;
+}
+
+static char *apr_error_string(apr_status_t statcode)
+{
+ switch (statcode) {
+ case APR_ENOSTAT:
+ return "Could not perform a stat on the file.";
+ case APR_ENOPOOL:
+ return "A new pool could not be created.";
+ case APR_EBADDATE:
+ return "An invalid date has been provided";
+ case APR_EINVALSOCK:
+ return "An invalid socket was returned";
+ case APR_ENOPROC:
+ return "No process was provided and one was required.";
+ case APR_ENOTIME:
+ return "No time was provided and one was required.";
+ case APR_ENODIR:
+ return "No directory was provided and one was required.";
+ case APR_ENOLOCK:
+ return "No lock was provided and one was required.";
+ case APR_ENOPOLL:
+ return "No poll structure was provided and one was required.";
+ case APR_ENOSOCKET:
+ return "No socket was provided and one was required.";
+ case APR_ENOTHREAD:
+ return "No thread was provided and one was required.";
+ case APR_ENOTHDKEY:
+ return "No thread key structure was provided and one was required.";
+ case APR_ENOSHMAVAIL:
+ return "No shared memory is currently available";
+ case APR_EDSOOPEN:
+#if APR_HAS_DSO && defined(HAVE_LIBDL)
+ return dlerror();
+#else
+ return "DSO load failed";
+#endif /* HAVE_LIBDL */
+ case APR_EBADIP:
+ return "The specified IP address is invalid.";
+ case APR_EBADMASK:
+ return "The specified network mask is invalid.";
+ case APR_ESYMNOTFOUND:
+ return "Could not find the requested symbol.";
+ case APR_ENOTENOUGHENTROPY:
+ return "Not enough entropy to continue.";
+ case APR_INCHILD:
+ return
+ "Your code just forked, and you are currently executing in the "
+ "child process";
+ case APR_INPARENT:
+ return
+ "Your code just forked, and you are currently executing in the "
+ "parent process";
+ case APR_DETACH:
+ return "The specified thread is detached";
+ case APR_NOTDETACH:
+ return "The specified thread is not detached";
+ case APR_CHILD_DONE:
+ return "The specified child process is done executing";
+ case APR_CHILD_NOTDONE:
+ return "The specified child process is not done executing";
+ case APR_TIMEUP:
+ return "The timeout specified has expired";
+ case APR_INCOMPLETE:
+ return "Partial results are valid but processing is incomplete";
+ case APR_BADCH:
+ return "Bad character specified on command line";
+ case APR_BADARG:
+ return "Missing parameter for the specified command line option";
+ case APR_EOF:
+ return "End of file found";
+ case APR_NOTFOUND:
+ return "Could not find specified socket in poll list.";
+ case APR_ANONYMOUS:
+ return "Shared memory is implemented anonymously";
+ case APR_FILEBASED:
+ return "Shared memory is implemented using files";
+ case APR_KEYBASED:
+ return "Shared memory is implemented using a key system";
+ case APR_EINIT:
+ return
+ "There is no error, this value signifies an initialized "
+ "error code";
+ case APR_ENOTIMPL:
+ return "This function has not been implemented on this platform";
+ case APR_EMISMATCH:
+ return "passwords do not match";
+ case APR_EABSOLUTE:
+ return "The given path is absolute";
+ case APR_ERELATIVE:
+ return "The given path is relative";
+ case APR_EINCOMPLETE:
+ return "The given path is incomplete";
+ case APR_EABOVEROOT:
+ return "The given path was above the root path";
+ case APR_EBADPATH:
+ return "The given path is misformatted or contained invalid characters";
+ case APR_EPATHWILD:
+ return "The given path contained wildcard characters";
+ case APR_EBUSY:
+ return "The given lock was busy.";
+ case APR_EPROC_UNKNOWN:
+ return "The process is not recognized.";
+ case APR_EGENERAL:
+ return "Internal error (specific information not available)";
+ default:
+ return "Error string not specified yet";
+ }
+}
+
+
+#ifdef OS2
+#include <ctype.h>
+
+int apr_canonical_error(apr_status_t err);
+
+static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
+{
+ char result[200];
+ unsigned char message[HUGE_STRING_LEN];
+ ULONG len;
+ char *pos;
+ int c;
+
+ if (err >= 10000 && err < 12000) { /* socket error codes */
+ return stuffbuffer(buf, bufsize,
+ strerror(apr_canonical_error(err+APR_OS_START_SYSERR)));
+ }
+ else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err,
+ "OSO001.MSG", &len) == 0) {
+ len--;
+ message[len] = 0;
+ pos = result;
+
+ if (len >= sizeof(result))
+ len = sizeof(result) - 1;
+
+ for (c=0; c<len; c++) {
+ /* skip multiple whitespace */
+ while (apr_isspace(message[c]) && apr_isspace(message[c+1]))
+ c++;
+ *(pos++) = apr_isspace(message[c]) ? ' ' : message[c];
+ }
+
+ *pos = 0;
+ }
+ else {
+ sprintf(result, "OS/2 error %d", err);
+ }
+
+ /* Stuff the string into the caller supplied buffer, then return
+ * a pointer to it.
+ */
+ return stuffbuffer(buf, bufsize, result);
+}
+
+#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
+
+static const struct {
+ apr_status_t code;
+ const char *msg;
+} gaErrorList[] = {
+ {WSAEINTR, "Interrupted system call"},
+ {WSAEBADF, "Bad file number"},
+ {WSAEACCES, "Permission denied"},
+ {WSAEFAULT, "Bad address"},
+ {WSAEINVAL, "Invalid argument"},
+ {WSAEMFILE, "Too many open sockets"},
+ {WSAEWOULDBLOCK, "Operation would block"},
+ {WSAEINPROGRESS, "Operation now in progress"},
+ {WSAEALREADY, "Operation already in progress"},
+ {WSAENOTSOCK, "Socket operation on non-socket"},
+ {WSAEDESTADDRREQ, "Destination address required"},
+ {WSAEMSGSIZE, "Message too long"},
+ {WSAEPROTOTYPE, "Protocol wrong type for socket"},
+ {WSAENOPROTOOPT, "Bad protocol option"},
+ {WSAEPROTONOSUPPORT, "Protocol not supported"},
+ {WSAESOCKTNOSUPPORT, "Socket type not supported"},
+ {WSAEOPNOTSUPP, "Operation not supported on socket"},
+ {WSAEPFNOSUPPORT, "Protocol family not supported"},
+ {WSAEAFNOSUPPORT, "Address family not supported"},
+ {WSAEADDRINUSE, "Address already in use"},
+ {WSAEADDRNOTAVAIL, "Can't assign requested address"},
+ {WSAENETDOWN, "Network is down"},
+ {WSAENETUNREACH, "Network is unreachable"},
+ {WSAENETRESET, "Net connection reset"},
+ {WSAECONNABORTED, "Software caused connection abort"},
+ {WSAECONNRESET, "Connection reset by peer"},
+ {WSAENOBUFS, "No buffer space available"},
+ {WSAEISCONN, "Socket is already connected"},
+ {WSAENOTCONN, "Socket is not connected"},
+ {WSAESHUTDOWN, "Can't send after socket shutdown"},
+ {WSAETOOMANYREFS, "Too many references, can't splice"},
+ {WSAETIMEDOUT, "Connection timed out"},
+ {WSAECONNREFUSED, "Connection refused"},
+ {WSAELOOP, "Too many levels of symbolic links"},
+ {WSAENAMETOOLONG, "File name too long"},
+ {WSAEHOSTDOWN, "Host is down"},
+ {WSAEHOSTUNREACH, "No route to host"},
+ {WSAENOTEMPTY, "Directory not empty"},
+ {WSAEPROCLIM, "Too many processes"},
+ {WSAEUSERS, "Too many users"},
+ {WSAEDQUOT, "Disc quota exceeded"},
+ {WSAESTALE, "Stale NFS file handle"},
+ {WSAEREMOTE, "Too many levels of remote in path"},
+ {WSASYSNOTREADY, "Network system is unavailable"},
+ {WSAVERNOTSUPPORTED, "Winsock version out of range"},
+ {WSANOTINITIALISED, "WSAStartup not yet called"},
+ {WSAEDISCON, "Graceful shutdown in progress"},
+ {WSAHOST_NOT_FOUND, "Host not found"},
+ {WSANO_DATA, "No host data of that type was found"},
+ {0, NULL}
+};
+
+
+static char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode)
+{
+ apr_size_t len=0, i;
+
+#ifndef NETWARE
+#ifndef _WIN32_WCE
+ len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ errcode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ buf,
+ (DWORD)bufsize,
+ NULL);
+#else /* _WIN32_WCE speaks unicode */
+ LPTSTR msg = (LPTSTR) buf;
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ errcode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ msg,
+ (DWORD) (bufsize/sizeof(TCHAR)),
+ NULL);
+ /* in-place convert to US-ASCII, substituting '?' for non ASCII */
+ for(i = 0; i <= len; i++) {
+ if (msg[i] < 0x80 && msg[i] >= 0) {
+ buf[i] = (char) msg[i];
+ } else {
+ buf[i] = '?';
+ }
+ }
+#endif
+#endif
+
+ if (!len) {
+ for (i = 0; gaErrorList[i].msg; ++i) {
+ if (gaErrorList[i].code == errcode) {
+ apr_cpystrn(buf, gaErrorList[i].msg, bufsize);
+ len = strlen(buf);
+ break;
+ }
+ }
+ }
+
+ if (len) {
+ /* FormatMessage put the message in the buffer, but it may
+ * have embedded a newline (\r\n), and possible more than one.
+ * Remove the newlines replacing them with a space. This is not
+ * as visually perfect as moving all the remaining message over,
+ * but more efficient.
+ */
+ i = len;
+ while (i) {
+ i--;
+ if ((buf[i] == '\r') || (buf[i] == '\n'))
+ buf[i] = ' ';
+ }
+ }
+ else {
+ /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message.
+ */
+ apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode);
+ }
+
+ return buf;
+}
+
+#else
+/* On Unix, apr_os_strerror() handles error codes from the resolver
+ * (h_errno).
+ */
+static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
+{
+#ifdef HAVE_HSTRERROR
+ return stuffbuffer(buf, bufsize, hstrerror(err));
+#else /* HAVE_HSTRERROR */
+ const char *msg;
+
+ switch(err) {
+ case HOST_NOT_FOUND:
+ msg = "Unknown host";
+ break;
+#if defined(NO_DATA)
+ case NO_DATA:
+#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS)
+ case NO_ADDRESS:
+#endif
+ msg = "No address for host";
+ break;
+#elif defined(NO_ADDRESS)
+ case NO_ADDRESS:
+ msg = "No address for host";
+ break;
+#endif /* NO_DATA */
+ default:
+ msg = "Unrecognized resolver error";
+ }
+ return stuffbuffer(buf, bufsize, msg);
+#endif /* HAVE_STRERROR */
+}
+#endif
+
+#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS)
+/* AIX and Tru64 style */
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ if (strerror_r(statcode, buf, bufsize) < 0) {
+ return stuffbuffer(buf, bufsize,
+ "APR does not understand this error code");
+ }
+ else {
+ return buf;
+ }
+}
+#elif defined(HAVE_STRERROR_R)
+/* glibc style */
+
+/* BeOS has the function available, but it doesn't provide
+ * the prototype publicly (doh!), so to avoid a build warning
+ * we add a suitable prototype here.
+ */
+#if defined(BEOS)
+const char *strerror_r(apr_status_t, char *, apr_size_t);
+#endif
+
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ const char *msg;
+
+ buf[0] = '\0';
+ msg = strerror_r(statcode, buf, bufsize);
+ if (buf[0] == '\0') { /* libc didn't use our buffer */
+ return stuffbuffer(buf, bufsize, msg);
+ }
+ else {
+ return buf;
+ }
+}
+#else
+/* plain old strerror();
+ * thread-safe on some platforms (e.g., Solaris, OS/390)
+ */
+static char *native_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+#ifdef _WIN32_WCE
+ static char err[32];
+ sprintf(err, "Native Error #%d", statcode);
+ return stuffbuffer(buf, bufsize, err);
+#else
+ const char *err = strerror(statcode);
+ if (err) {
+ return stuffbuffer(buf, bufsize, err);
+ } else {
+ return stuffbuffer(buf, bufsize,
+ "APR does not understand this error code");
+ }
+#endif
+}
+#endif
+
+APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf,
+ apr_size_t bufsize)
+{
+ if (statcode < APR_OS_START_ERROR) {
+ return native_strerror(statcode, buf, bufsize);
+ }
+ else if (statcode < APR_OS_START_USERERR) {
+ return stuffbuffer(buf, bufsize, apr_error_string(statcode));
+ }
+ else if (statcode < APR_OS_START_EAIERR) {
+ return stuffbuffer(buf, bufsize, "APR does not understand this error code");
+ }
+ else if (statcode < APR_OS_START_SYSERR) {
+#if defined(HAVE_GAI_STRERROR)
+ statcode -= APR_OS_START_EAIERR;
+#if defined(NEGATIVE_EAI)
+ statcode = -statcode;
+#endif
+ return stuffbuffer(buf, bufsize, gai_strerror(statcode));
+#else
+ return stuffbuffer(buf, bufsize, "APR does not understand this error code");
+#endif
+ }
+ else {
+ return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR);
+ }
+}
+
diff --git a/misc/unix/getopt.c b/misc/unix/getopt.c
new file mode 100644
index 0000000..24be3c8
--- /dev/null
+++ b/misc/unix/getopt.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * 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.
+ */
+
+#include "apr_arch_misc.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+
+#define EMSG ""
+
+APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont,
+ int argc, const char *const *argv)
+{
+ void *argv_buff;
+
+ *os = apr_palloc(cont, sizeof(apr_getopt_t));
+ (*os)->cont = cont;
+ (*os)->reset = 0;
+ (*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
+ (*os)->errarg = (void*)(stderr);
+
+ (*os)->place = EMSG;
+ (*os)->argc = argc;
+
+ /* The argv parameter must be compatible with main()'s argv, since
+ that's the primary purpose of this function. But people might
+ want to use this function with arrays other than the main argv,
+ and we shouldn't touch the caller's data. So we copy. */
+ argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *));
+ memcpy(argv_buff, argv, argc * sizeof(const char *));
+ (*os)->argv = argv_buff;
+ (*os)->argv[argc] = NULL;
+
+ (*os)->interleave = 0;
+ (*os)->ind = 1;
+ (*os)->skip_start = 1;
+ (*os)->skip_end = 1;
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts,
+ char *optch, const char **optarg)
+{
+ const char *oli; /* option letter list index */
+
+ if (os->reset || !*os->place) { /* update scanning pointer */
+ os->reset = 0;
+ if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
+ os->place = EMSG;
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ if (os->place[1] && *++os->place == '-') { /* found "--" */
+ ++os->ind;
+ os->place = EMSG;
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ } /* option letter okay? */
+ if ((os->opt = (int) *os->place++) == (int) ':' ||
+ !(oli = strchr(opts, os->opt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (os->opt == (int) '-') {
+ *optch = os->opt;
+ return (APR_EOF);
+ }
+ if (!*os->place)
+ ++os->ind;
+ if (os->errfn && *opts != ':') {
+ (os->errfn)(os->errarg, "%s: illegal option -- %c\n",
+ apr_filepath_name_get(*os->argv), os->opt);
+ }
+ *optch = os->opt;
+ return (APR_BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ *optarg = NULL;
+ if (!*os->place)
+ ++os->ind;
+ }
+ else { /* need an argument */
+ if (*os->place) /* no white space */
+ *optarg = os->place;
+ else if (os->argc <= ++os->ind) { /* no arg */
+ os->place = EMSG;
+ if (*opts == ':') {
+ *optch = os->opt;
+ return (APR_BADARG);
+ }
+ if (os->errfn) {
+ (os->errfn)(os->errarg,
+ "%s: option requires an argument -- %c\n",
+ apr_filepath_name_get(*os->argv), os->opt);
+ }
+ *optch = os->opt;
+ return (APR_BADCH);
+ }
+ else /* white space */
+ *optarg = os->argv[os->ind];
+ os->place = EMSG;
+ ++os->ind;
+ }
+ *optch = os->opt;
+ return APR_SUCCESS;
+}
+
+/* Reverse the sequence argv[start..start+len-1]. */
+static void reverse(const char **argv, int start, int len)
+{
+ const char *temp;
+
+ for (; len >= 2; start++, len -= 2) {
+ temp = argv[start];
+ argv[start] = argv[start + len - 1];
+ argv[start + len - 1] = temp;
+ }
+}
+
+/*
+ * Permute os->argv with the goal that non-option arguments will all
+ * appear at the end. os->skip_start is where we started skipping
+ * non-option arguments, os->skip_end is where we stopped, and os->ind
+ * is where we are now.
+ */
+static void permute(apr_getopt_t *os)
+{
+ int len1 = os->skip_end - os->skip_start;
+ int len2 = os->ind - os->skip_end;
+
+ if (os->interleave) {
+ /*
+ * Exchange the sequences argv[os->skip_start..os->skip_end-1] and
+ * argv[os->skip_end..os->ind-1]. The easiest way to do that is
+ * to reverse the entire range and then reverse the two
+ * sub-ranges.
+ */
+ reverse(os->argv, os->skip_start, len1 + len2);
+ reverse(os->argv, os->skip_start, len2);
+ reverse(os->argv, os->skip_start + len2, len1);
+ }
+
+ /* Reset skip range to the new location of the non-option sequence. */
+ os->skip_start += len2;
+ os->skip_end += len2;
+}
+
+/* Helper function to print out an error involving a long option */
+static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str,
+ apr_status_t status)
+{
+ if (os->errfn)
+ (os->errfn)(os->errarg, "%s: %s: %s\n",
+ apr_filepath_name_get(*os->argv), err, str);
+ return status;
+}
+
+/* Helper function to print out an error involving a short option */
+static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch,
+ apr_status_t status)
+{
+ if (os->errfn)
+ (os->errfn)(os->errarg, "%s: %s: %c\n",
+ apr_filepath_name_get(*os->argv), err, ch);
+ return status;
+}
+
+APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
+ const apr_getopt_option_t *opts,
+ int *optch, const char **optarg)
+{
+ const char *p;
+ int i;
+
+ /* Let the calling program reset option processing. */
+ if (os->reset) {
+ os->place = EMSG;
+ os->ind = 1;
+ os->reset = 0;
+ }
+
+ /*
+ * We can be in one of two states: in the middle of processing a
+ * run of short options, or about to process a new argument.
+ * Since the second case can lead to the first one, handle that
+ * one first. */
+ p = os->place;
+ if (*p == '\0') {
+ /* If we are interleaving, skip non-option arguments. */
+ if (os->interleave) {
+ while (os->ind < os->argc && *os->argv[os->ind] != '-')
+ os->ind++;
+ os->skip_end = os->ind;
+ }
+ if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
+ os->ind = os->skip_start;
+ return APR_EOF;
+ }
+
+ p = os->argv[os->ind++] + 1;
+ if (*p == '-' && p[1] != '\0') { /* Long option */
+ /* Search for the long option name in the caller's table. */
+ apr_size_t len = 0;
+
+ p++;
+ for (i = 0; ; i++) {
+ if (opts[i].optch == 0) /* No match */
+ return serr(os, "invalid option", p - 2, APR_BADCH);
+
+ if (opts[i].name) {
+ len = strlen(opts[i].name);
+ if (strncmp(p, opts[i].name, len) == 0
+ && (p[len] == '\0' || p[len] == '='))
+ break;
+ }
+ }
+ *optch = opts[i].optch;
+
+ if (opts[i].has_arg) {
+ if (p[len] == '=') /* Argument inline */
+ *optarg = p + len + 1;
+ else {
+ if (os->ind >= os->argc) /* Argument missing */
+ return serr(os, "missing argument", p - 2, APR_BADARG);
+ else /* Argument in next arg */
+ *optarg = os->argv[os->ind++];
+ }
+ } else {
+ *optarg = NULL;
+ if (p[len] == '=')
+ return serr(os, "erroneous argument", p - 2, APR_BADARG);
+ }
+ permute(os);
+ return APR_SUCCESS;
+ } else {
+ if (*p == '-') { /* Bare "--"; we're done */
+ permute(os);
+ os->ind = os->skip_start;
+ return APR_EOF;
+ }
+ else
+ if (*p == '\0') /* Bare "-" is illegal */
+ return serr(os, "invalid option", p, APR_BADCH);
+ }
+ }
+
+ /*
+ * Now we're in a run of short options, and *p is the next one.
+ * Look for it in the caller's table.
+ */
+ for (i = 0; ; i++) {
+ if (opts[i].optch == 0) /* No match */
+ return cerr(os, "invalid option character", *p, APR_BADCH);
+
+ if (*p == opts[i].optch)
+ break;
+ }
+ *optch = *p++;
+
+ if (opts[i].has_arg) {
+ if (*p != '\0') /* Argument inline */
+ *optarg = p;
+ else {
+ if (os->ind >= os->argc) /* Argument missing */
+ return cerr(os, "missing argument", *optch, APR_BADARG);
+ else /* Argument in next arg */
+ *optarg = os->argv[os->ind++];
+ }
+ os->place = EMSG;
+ } else {
+ *optarg = NULL;
+ os->place = p;
+ }
+
+ permute(os);
+ return APR_SUCCESS;
+}
diff --git a/misc/unix/otherchild.c b/misc/unix/otherchild.c
new file mode 100644
index 0000000..427a57e
--- /dev/null
+++ b/misc/unix/otherchild.c
@@ -0,0 +1,221 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_arch_misc.h"
+#include "apr_arch_threadproc.h"
+#include "apr_arch_file_io.h"
+
+#if APR_HAS_OTHER_CHILD
+
+#ifdef HAVE_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if APR_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef BEOS
+#include <sys/socket.h> /* for fd_set definition! */
+#endif
+
+static apr_other_child_rec_t *other_children = NULL;
+
+static apr_status_t other_child_cleanup(void *data)
+{
+ apr_other_child_rec_t **pocr, *nocr;
+
+ for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
+ if ((*pocr)->data == data) {
+ nocr = (*pocr)->next;
+ (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1);
+ *pocr = nocr;
+ /* XXX: um, well we've just wasted some space in pconf ? */
+ return APR_SUCCESS;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
+ void (*maintenance) (int reason, void *, int status),
+ void *data, apr_file_t *write_fd, apr_pool_t *p)
+{
+ apr_other_child_rec_t *ocr;
+
+ ocr = apr_palloc(p, sizeof(*ocr));
+ ocr->p = p;
+ ocr->proc = proc;
+ ocr->maintenance = maintenance;
+ ocr->data = data;
+ if (write_fd == NULL) {
+ ocr->write_fd = (apr_os_file_t) -1;
+ }
+ else {
+#ifdef WIN32
+ /* This should either go away as part of eliminating apr_proc_probe_writable_fds
+ * or write_fd should point to an apr_file_t
+ */
+ ocr->write_fd = write_fd->filehand;
+#else
+ ocr->write_fd = write_fd->filedes;
+#endif
+
+ }
+ ocr->next = other_children;
+ other_children = ocr;
+ apr_pool_cleanup_register(p, ocr->data, other_child_cleanup,
+ apr_pool_cleanup_null);
+}
+
+APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
+{
+ apr_other_child_rec_t *cur;
+
+ cur = other_children;
+ while (cur) {
+ if (cur->data == data) {
+ break;
+ }
+ cur = cur->next;
+ }
+
+ /* segfault if this function called with invalid parm */
+ apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup);
+ other_child_cleanup(data);
+}
+
+APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
+ int reason,
+ int status)
+{
+ apr_other_child_rec_t *ocr, *nocr;
+
+ for (ocr = other_children; ocr; ocr = nocr) {
+ nocr = ocr->next;
+ if (ocr->proc->pid != proc->pid)
+ continue;
+
+ ocr->proc = NULL;
+ (*ocr->maintenance) (reason, ocr->data, status);
+ return APR_SUCCESS;
+ }
+ return APR_EPROC_UNKNOWN;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
+ int reason)
+{
+ /* Todo:
+ * Implement code to detect if pipes are still alive.
+ */
+#ifdef WIN32
+ DWORD status;
+
+ if (ocr->proc == NULL)
+ return;
+
+ if (!ocr->proc->hproc) {
+ /* Already mopped up, perhaps we apr_proc_kill'ed it,
+ * they should have already unregistered!
+ */
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+ else if (!GetExitCodeProcess(ocr->proc->hproc, &status)) {
+ CloseHandle(ocr->proc->hproc);
+ ocr->proc->hproc = NULL;
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+ else if (status == STILL_ACTIVE) {
+ (*ocr->maintenance) (reason, ocr->data, -1);
+ }
+ else {
+ CloseHandle(ocr->proc->hproc);
+ ocr->proc->hproc = NULL;
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
+ }
+
+#else /* ndef Win32 */
+ pid_t waitret;
+ int status;
+
+ if (ocr->proc == NULL)
+ return;
+
+ waitret = waitpid(ocr->proc->pid, &status, WNOHANG);
+ if (waitret == ocr->proc->pid) {
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
+ }
+ else if (waitret == 0) {
+ (*ocr->maintenance) (reason, ocr->data, -1);
+ }
+ else if (waitret == -1) {
+ /* uh what the heck? they didn't call unregister? */
+ ocr->proc = NULL;
+ (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
+ }
+#endif
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
+{
+ apr_other_child_rec_t *ocr, *next_ocr;
+
+ for (ocr = other_children; ocr; ocr = next_ocr) {
+ next_ocr = ocr->next;
+ apr_proc_other_child_refresh(ocr, reason);
+ }
+}
+
+#else /* !APR_HAS_OTHER_CHILD */
+
+APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
+ void (*maintenance) (int reason, void *, int status),
+ void *data, apr_file_t *write_fd, apr_pool_t *p)
+{
+ return;
+}
+
+APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
+{
+ return;
+}
+
+APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
+ int reason,
+ int status)
+{
+ return APR_ENOTIMPL;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
+ int reason)
+{
+ return;
+}
+
+APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
+{
+ return;
+}
+
+#endif /* APR_HAS_OTHER_CHILD */
diff --git a/misc/unix/rand.c b/misc/unix/rand.c
new file mode 100644
index 0000000..c0567a6
--- /dev/null
+++ b/misc/unix/rand.c
@@ -0,0 +1,302 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define APR_WANT_MEMFUNC
+#include "apr_want.h"
+#include "apr_general.h"
+
+#include "apr_arch_misc.h"
+#include <sys/stat.h>
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if APR_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if defined(HAVE_UUID_H)
+#include <uuid.h>
+#elif defined(HAVE_UUID_UUID_H)
+#include <uuid/uuid.h>
+#elif defined(HAVE_SYS_UUID_H)
+#include <sys/uuid.h>
+#endif
+
+#if defined(SYS_RANDOM)
+#if defined(HAVE_SYS_RANDOM_H) && \
+ defined(HAVE_GETRANDOM)
+
+#include <sys/random.h>
+#define USE_GETRANDOM
+
+#elif defined(HAVE_SYS_SYSCALL_H) && \
+ defined(HAVE_LINUX_RANDOM_H) && \
+ defined(HAVE_DECL_SYS_GETRANDOM) && \
+ HAVE_DECL_SYS_GETRANDOM
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/random.h>
+#define getrandom(buf, buflen, flags) \
+ syscall(SYS_getrandom, (buf), (buflen), (flags))
+#define USE_GETRANDOM
+
+#endif /* HAVE_SYS_RANDOM_H */
+#endif /* SYS_RANDOM */
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#if APR_HAS_OS_UUID
+
+#if defined(HAVE_UUID_CREATE)
+
+APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
+{
+ uint32_t rv;
+ uuid_t g;
+
+ uuid_create(&g, &rv);
+
+ if (rv != uuid_s_ok)
+ return APR_EGENERAL;
+
+ memcpy(uuid_data, &g, sizeof(uuid_t));
+
+ return APR_SUCCESS;
+}
+
+#elif defined(HAVE_UUID_GENERATE)
+
+APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
+{
+ uuid_t g;
+
+ uuid_generate(g);
+
+ memcpy(uuid_data, g, sizeof(uuid_t));
+
+ return APR_SUCCESS;
+}
+#endif
+
+#endif /* APR_HAS_OS_UUID */
+
+#if APR_HAS_RANDOM
+
+APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
+ apr_size_t length)
+{
+#if defined(HAVE_EGD)
+ /* use EGD-compatible socket daemon (such as EGD or PRNGd).
+ * message format:
+ * 0x00 (get entropy level)
+ * 0xMM (msb) 0xmm 0xll 0xLL (lsb)
+ * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
+ * 0xMM (bytes granted) MM bytes
+ * 0x02 (read entropy blocking) 0xNN (bytes desired)
+ * [block] NN bytes
+ * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
+ * NN bytes
+ * (no response - write only)
+ * 0x04 (report PID)
+ * 0xMM (length of PID string, not null-terminated) MM chars
+ */
+ static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
+ const char **egdsockname = NULL;
+
+ int egd_socket, egd_path_len, rv, bad_errno;
+ struct sockaddr_un addr;
+ apr_socklen_t egd_addr_len;
+ apr_size_t resp_expected;
+ unsigned char req[2], resp[255];
+ unsigned char *curbuf = buf;
+
+ for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
+ egd_path_len = strlen(*egdsockname);
+
+ if (egd_path_len > sizeof(addr.sun_path)) {
+ return APR_EINVAL;
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ memcpy(addr.sun_path, *egdsockname, egd_path_len);
+ egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) +
+ egd_path_len;
+
+ egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
+
+ if (egd_socket == -1) {
+ return errno;
+ }
+
+ rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
+
+ if (rv == -1) {
+ bad_errno = errno;
+ continue;
+ }
+
+ /* EGD can only return 255 bytes of data at a time. Silly. */
+ while (length > 0) {
+ apr_ssize_t srv;
+ req[0] = 2; /* We'll block for now. */
+ req[1] = length > 255 ? 255: length;
+
+ srv = write(egd_socket, req, 2);
+ if (srv == -1) {
+ bad_errno = errno;
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ break;
+ }
+
+ if (srv != 2) {
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ return APR_EGENERAL;
+ }
+
+ resp_expected = req[1];
+ srv = read(egd_socket, resp, resp_expected);
+ if (srv == -1) {
+ bad_errno = errno;
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ return bad_errno;
+ }
+
+ memcpy(curbuf, resp, srv);
+ curbuf += srv;
+ length -= srv;
+ }
+
+ shutdown(egd_socket, SHUT_RDWR);
+ close(egd_socket);
+ }
+
+ if (length > 0) {
+ /* We must have iterated through the list of sockets,
+ * and no go. Return the errno.
+ */
+ return bad_errno;
+ }
+
+#elif defined(SYS_RANDOM) && defined(USE_GETRANDOM)
+
+ do {
+ int rc;
+
+ rc = getrandom(buf, length, 0);
+ if (rc == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return errno;
+ }
+
+ buf += rc;
+ length -= rc;
+ } while (length > 0);
+
+#elif defined(SYS_RANDOM) && defined(HAVE_ARC4RANDOM_BUF)
+
+ arc4random_buf(buf, length);
+
+#elif defined(DEV_RANDOM)
+
+ int fd = -1;
+
+ /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
+ * gives EOF, so reading 'length' bytes may require opening the
+ * device several times. */
+ do {
+ apr_ssize_t rc;
+
+ if (fd == -1)
+ if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
+ return errno;
+
+ do {
+ rc = read(fd, buf, length);
+ } while (rc == -1 && errno == EINTR);
+
+ if (rc < 0) {
+ int errnum = errno;
+ close(fd);
+ return errnum;
+ }
+ else if (rc == 0) {
+ close(fd);
+ fd = -1; /* force open() again */
+ }
+ else {
+ buf += rc;
+ length -= rc;
+ }
+ } while (length > 0);
+
+ close(fd);
+
+#elif defined(OS2)
+
+ static UCHAR randbyte();
+ unsigned int idx;
+
+ for (idx=0; idx<length; idx++)
+ buf[idx] = randbyte();
+
+#elif defined(HAVE_TRUERAND) /* use truerand */
+
+ extern int randbyte(void); /* from the truerand library */
+ unsigned int idx;
+
+ /* this will increase the startup time of the server, unfortunately...
+ * (generating 20 bytes takes about 8 seconds)
+ */
+ for (idx=0; idx<length; idx++)
+ buf[idx] = (unsigned char) randbyte();
+
+#else
+
+#error APR_HAS_RANDOM defined with no implementation
+
+#endif /* DEV_RANDOM */
+
+ return APR_SUCCESS;
+}
+
+#undef STR
+#undef XSTR
+
+#ifdef OS2
+#include "randbyte_os2.inc"
+#endif
+
+#endif /* APR_HAS_RANDOM */
diff --git a/misc/unix/randbyte_os2.inc b/misc/unix/randbyte_os2.inc
new file mode 100644
index 0000000..4020e31
--- /dev/null
+++ b/misc/unix/randbyte_os2.inc
@@ -0,0 +1,123 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* The high resolution timer API provides access to the hardware timer
+ * running at around 1.1MHz. The amount this changes in a time slice is
+ * varies randomly due to system events, hardware interrupts etc
+ */
+static UCHAR randbyte_hrtimer()
+{
+ QWORD t1, t2;
+ UCHAR byte;
+
+ DosTmrQueryTime(&t1);
+ DosSleep(5);
+ DosTmrQueryTime(&t2);
+
+ byte = (t2.ulLo - t1.ulLo) & 0xFF;
+ byte ^= (t2.ulLo - t1.ulLo) >> 8;
+ return byte;
+}
+
+
+
+/* A bunch of system information like memory & process stats.
+ * Not highly random but every bit helps....
+ */
+static UCHAR randbyte_sysinfo()
+{
+ UCHAR byte = 0;
+ UCHAR SysVars[100];
+ int b;
+
+ DosQuerySysInfo(1, QSV_FOREGROUND_PROCESS, SysVars, sizeof(SysVars));
+
+ for (b = 0; b < 100; b++) {
+ byte ^= SysVars[b];
+ }
+
+ return byte;
+}
+
+
+
+/* Similar in concept to randbyte_hrtimer() but accesses the CPU's internal
+ * counters which run at the CPU's MHz speed. We get separate
+ * idle / busy / interrupt cycle counts which should provide very good
+ * randomness due to interference of hardware events.
+ * This only works on newer CPUs (at least PPro or K6) and newer OS/2 versions
+ * which is why it's run-time linked.
+ */
+
+static APIRET APIENTRY(*DosPerfSysCall) (ULONG ulCommand, ULONG ulParm1,
+ ULONG ulParm2, ULONG ulParm3) = NULL;
+static HMODULE hDoscalls = 0;
+#define CMD_KI_RDCNT (0x63)
+
+typedef struct _CPUUTIL {
+ ULONG ulTimeLow; /* Low 32 bits of time stamp */
+ ULONG ulTimeHigh; /* High 32 bits of time stamp */
+ ULONG ulIdleLow; /* Low 32 bits of idle time */
+ ULONG ulIdleHigh; /* High 32 bits of idle time */
+ ULONG ulBusyLow; /* Low 32 bits of busy time */
+ ULONG ulBusyHigh; /* High 32 bits of busy time */
+ ULONG ulIntrLow; /* Low 32 bits of interrupt time */
+ ULONG ulIntrHigh; /* High 32 bits of interrupt time */
+} CPUUTIL;
+
+
+static UCHAR randbyte_perf()
+{
+ UCHAR byte = 0;
+ CPUUTIL util;
+ int c;
+
+ if (hDoscalls == 0) {
+ char failed_module[20];
+ ULONG rc;
+
+ rc = DosLoadModule(failed_module, sizeof(failed_module), "DOSCALLS",
+ &hDoscalls);
+
+ if (rc == 0) {
+ rc = DosQueryProcAddr(hDoscalls, 976, NULL, (PFN *)&DosPerfSysCall);
+
+ if (rc) {
+ DosPerfSysCall = NULL;
+ }
+ }
+ }
+
+ if (DosPerfSysCall) {
+ if (DosPerfSysCall(CMD_KI_RDCNT, (ULONG)&util, 0, 0) == 0) {
+ for (c = 0; c < sizeof(util); c++) {
+ byte ^= ((UCHAR *)&util)[c];
+ }
+ }
+ else {
+ DosPerfSysCall = NULL;
+ }
+ }
+
+ return byte;
+}
+
+
+
+static UCHAR randbyte()
+{
+ return randbyte_hrtimer() ^ randbyte_sysinfo() ^ randbyte_perf();
+}
diff --git a/misc/unix/start.c b/misc/unix/start.c
new file mode 100644
index 0000000..4b8ad99
--- /dev/null
+++ b/misc/unix/start.c
@@ -0,0 +1,89 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_signal.h"
+#include "apr_atomic.h"
+
+#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */
+#include "apr_arch_internal_time.h"
+
+
+APR_DECLARE(apr_status_t) apr_app_initialize(int *argc,
+ const char * const * *argv,
+ const char * const * *env)
+{
+ /* An absolute noop. At present, only Win32 requires this stub, but it's
+ * required in order to move command arguments passed through the service
+ * control manager into the process, and it's required to fix the char*
+ * data passed in from win32 unicode into utf-8, win32's apr internal fmt.
+ */
+ return apr_initialize();
+}
+
+static int initialized = 0;
+
+APR_DECLARE(apr_status_t) apr_initialize(void)
+{
+ apr_pool_t *pool;
+ apr_status_t status;
+
+ if (initialized++) {
+ return APR_SUCCESS;
+ }
+
+#if !defined(BEOS) && !defined(OS2)
+ apr_proc_mutex_unix_setup_lock();
+ apr_unix_setup_time();
+#endif
+
+ if ((status = apr_pool_initialize()) != APR_SUCCESS)
+ return status;
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return APR_ENOPOOL;
+ }
+
+ apr_pool_tag(pool, "apr_initialize");
+
+ /* apr_atomic_init() used to be called from here aswell.
+ * Pools rely on mutexes though, which can be backed by
+ * atomics. Due to this circular dependency
+ * apr_pool_initialize() is taking care of calling
+ * apr_atomic_init() at the correct time.
+ */
+
+ apr_signal_init(pool);
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE_NONSTD(void) apr_terminate(void)
+{
+ initialized--;
+ if (initialized) {
+ return;
+ }
+ apr_pool_terminate();
+
+}
+
+APR_DECLARE(void) apr_terminate2(void)
+{
+ apr_terminate();
+}
diff --git a/misc/unix/version.c b/misc/unix/version.c
new file mode 100644
index 0000000..2f111bf
--- /dev/null
+++ b/misc/unix/version.c
@@ -0,0 +1,35 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_version.h"
+#include "apr_general.h" /* for APR_STRINGIFY */
+
+APR_DECLARE(void) apr_version(apr_version_t *pvsn)
+{
+ pvsn->major = APR_MAJOR_VERSION;
+ pvsn->minor = APR_MINOR_VERSION;
+ pvsn->patch = APR_PATCH_VERSION;
+#ifdef APR_IS_DEV_VERSION
+ pvsn->is_dev = 1;
+#else
+ pvsn->is_dev = 0;
+#endif
+}
+
+APR_DECLARE(const char *) apr_version_string(void)
+{
+ return APR_VERSION_STRING;
+}
diff --git a/misc/win32/apr_app.c b/misc/win32/apr_app.c
new file mode 100644
index 0000000..4b1874f
--- /dev/null
+++ b/misc/win32/apr_app.c
@@ -0,0 +1,104 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Usage Notes:
+ *
+ * this module, and the misc/win32/utf8.c modules must be
+ * compiled APR_EXPORT_STATIC and linked to an application with
+ * the /entry:wmainCRTStartup flag (which this module kindly
+ * provides to the developer who links to libaprapp-1.lib).
+ * This module becomes the true wmain entry point, and passes
+ * utf-8 reformatted argv and env arrays to the application's
+ * main() function as if nothing happened.
+ *
+ * This module is only compatible with Unicode operating systems.
+ * Mixed (Win9x backwards compatible) binaries should refer instead
+ * to the apr_startup.c module.
+ *
+ * _dbg_malloc/realloc is used in place of the usual API, in order
+ * to convince the MSVCRT that it created these entities. If we
+ * do not create them as _CRT_BLOCK entities, the crt will fault
+ * on an assert. We are not worrying about the crt's locks here,
+ * since we are single threaded [so far].
+ */
+
+#include "apr_general.h"
+#include "ShellAPI.h"
+#include "wchar.h"
+#include "apr_arch_file_io.h"
+#include "assert.h"
+#include "apr_private.h"
+#include "apr_arch_misc.h"
+
+#pragma comment(linker,"/ENTRY:wmainCRTStartup")
+
+extern int main(int argc, const char **argv, const char **env);
+
+int wmain(int argc, const wchar_t **wargv, const wchar_t **wenv)
+{
+ char **argv;
+ char **env;
+ int envc;
+ int i;
+
+ (void)apr_wastrtoastr(&argv, wargv, argc);
+
+ envc = 0;
+ while (wenv[envc]) {
+ envc++;
+ }
+
+ /* Initial environment stored as single heap block, but uses
+ * separate heap entry for every environment variable
+ * after first change.
+ */
+ env = apr_malloc_dbg((envc + 1) * sizeof(char *), __FILE__, __LINE__);
+
+ for (i = 0; i < envc; i++) {
+ apr_size_t wcount;
+ apr_size_t envlen;
+
+ wcount = wcslen(wenv[i]) + 1;
+ envlen = (wcount - 1) * 3 + 1;
+
+ env[i] = apr_malloc_dbg(envlen, __FILE__, __LINE__);
+
+ (void)apr_conv_ucs2_to_utf8(wenv[i], &wcount, env[i], &envlen);
+ }
+
+ env[i] = NULL;
+
+ _environ = env;
+
+ /* MSVCRT will attempt to maintain the wide environment calls
+ * on _putenv(), which is bogus if we've passed a non-ascii
+ * string to _putenv(), since they use MultiByteToWideChar
+ * and breaking the implicit utf-8 assumption we've built.
+ *
+ * Reset _wenviron for good measure.
+ */
+ if (_wenviron) {
+ _wenviron = NULL;
+
+ /* There is no need to free _wenviron because MSVCRT
+ * automatically free 'initial' environment block.
+ */
+ }
+
+ apr_app_init_complete = 1;
+
+ return main(argc, argv, env);
+}
diff --git a/misc/win32/charset.c b/misc/win32/charset.c
new file mode 100644
index 0000000..41135b2
--- /dev/null
+++ b/misc/win32/charset.c
@@ -0,0 +1,55 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_portable.h"
+
+
+APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool)
+{
+ return apr_psprintf(pool, "CP%u", (unsigned) GetACP());
+}
+
+
+APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool)
+{
+#ifdef _UNICODE
+ int i;
+#endif
+#if defined(_WIN32_WCE)
+ LCID locale = GetUserDefaultLCID();
+#else
+ LCID locale = GetThreadLocale();
+#endif
+ int len = GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, NULL, 0);
+ char *cp = apr_palloc(pool, (len * sizeof(TCHAR)) + 2);
+ if (0 < GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, (TCHAR*) (cp + 2), len))
+ {
+ /* Fix up the returned number to make a valid codepage name of
+ the form "CPnnnn". */
+ cp[0] = 'C';
+ cp[1] = 'P';
+#ifdef _UNICODE
+ for(i = 0; i < len; i++) {
+ cp[i + 2] = (char) ((TCHAR*) (cp + 2))[i];
+ }
+#endif
+ return cp;
+ }
+
+ return apr_os_default_encoding(pool);
+}
diff --git a/misc/win32/env.c b/misc/win32/env.c
new file mode 100644
index 0000000..644f59b
--- /dev/null
+++ b/misc/win32/env.c
@@ -0,0 +1,192 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr.h"
+#include "apr_arch_misc.h"
+#include "apr_arch_utf8.h"
+#include "apr_env.h"
+#include "apr_errno.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+
+#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE)
+static apr_status_t widen_envvar_name (apr_wchar_t *buffer,
+ apr_size_t bufflen,
+ const char *envvar)
+{
+ apr_size_t inchars;
+ apr_status_t status;
+
+ inchars = strlen(envvar) + 1;
+ status = apr_conv_utf8_to_ucs2(envvar, &inchars, buffer, &bufflen);
+ if (status == APR_INCOMPLETE)
+ status = APR_ENAMETOOLONG;
+
+ return status;
+}
+#endif
+
+
+APR_DECLARE(apr_status_t) apr_env_get(char **value,
+ const char *envvar,
+ apr_pool_t *pool)
+{
+#if defined(_WIN32_WCE)
+ return APR_ENOTIMPL;
+#else
+ char *val = NULL;
+ DWORD size;
+
+#if APR_HAS_UNICODE_FS
+ IF_WIN_OS_IS_UNICODE
+ {
+ apr_wchar_t wenvvar[APR_PATH_MAX];
+ apr_size_t inchars, outchars;
+ apr_wchar_t *wvalue, dummy;
+ apr_status_t status;
+
+ status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar);
+ if (status)
+ return status;
+
+ SetLastError(0);
+ size = GetEnvironmentVariableW(wenvvar, &dummy, 0);
+ if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+ /* The environment variable doesn't exist. */
+ return APR_ENOENT;
+
+ if (size == 0) {
+ /* The environment value exists, but is zero-length. */
+ *value = apr_pstrdup(pool, "");
+ return APR_SUCCESS;
+ }
+
+ wvalue = apr_palloc(pool, size * sizeof(*wvalue));
+ size = GetEnvironmentVariableW(wenvvar, wvalue, size);
+
+ inchars = wcslen(wvalue) + 1;
+ outchars = 3 * inchars; /* Enough for any UTF-8 representation */
+ val = apr_palloc(pool, outchars);
+ status = apr_conv_ucs2_to_utf8(wvalue, &inchars, val, &outchars);
+ if (status)
+ return status;
+ }
+#endif
+#if APR_HAS_ANSI_FS
+ ELSE_WIN_OS_IS_ANSI
+ {
+ char dummy;
+
+ SetLastError(0);
+ size = GetEnvironmentVariableA(envvar, &dummy, 0);
+ if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+ /* The environment variable doesn't exist. */
+ return APR_ENOENT;
+
+ if (size == 0) {
+ /* The environment value exists, but is zero-length. */
+ *value = apr_pstrdup(pool, "");
+ return APR_SUCCESS;
+ }
+
+ val = apr_palloc(pool, size);
+ size = GetEnvironmentVariableA(envvar, val, size);
+ if (size == 0)
+ /* Mid-air collision?. Somebody must've changed the env. var. */
+ return APR_INCOMPLETE;
+ }
+#endif
+
+ *value = val;
+ return APR_SUCCESS;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_set(const char *envvar,
+ const char *value,
+ apr_pool_t *pool)
+{
+#if defined(_WIN32_WCE)
+ return APR_ENOTIMPL;
+#else
+#if APR_HAS_UNICODE_FS
+ IF_WIN_OS_IS_UNICODE
+ {
+ apr_wchar_t wenvvar[APR_PATH_MAX];
+ apr_wchar_t *wvalue;
+ apr_size_t inchars, outchars;
+ apr_status_t status;
+
+ status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar);
+ if (status)
+ return status;
+
+ outchars = inchars = strlen(value) + 1;
+ wvalue = apr_palloc(pool, outchars * sizeof(*wvalue));
+ status = apr_conv_utf8_to_ucs2(value, &inchars, wvalue, &outchars);
+ if (status)
+ return status;
+
+ if (!SetEnvironmentVariableW(wenvvar, wvalue))
+ return apr_get_os_error();
+ }
+#endif
+#if APR_HAS_ANSI_FS
+ ELSE_WIN_OS_IS_ANSI
+ {
+ if (!SetEnvironmentVariableA(envvar, value))
+ return apr_get_os_error();
+ }
+#endif
+
+ return APR_SUCCESS;
+#endif
+}
+
+
+APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool)
+{
+#if defined(_WIN32_WCE)
+ return APR_ENOTIMPL;
+#else
+#if APR_HAS_UNICODE_FS
+ IF_WIN_OS_IS_UNICODE
+ {
+ apr_wchar_t wenvvar[APR_PATH_MAX];
+ apr_status_t status;
+
+ status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar);
+ if (status)
+ return status;
+
+ if (!SetEnvironmentVariableW(wenvvar, NULL))
+ return apr_get_os_error();
+ }
+#endif
+#if APR_HAS_ANSI_FS
+ ELSE_WIN_OS_IS_ANSI
+ {
+ if (!SetEnvironmentVariableA(envvar, NULL))
+ return apr_get_os_error();
+ }
+#endif
+
+ return APR_SUCCESS;
+#endif
+}
diff --git a/misc/win32/internal.c b/misc/win32/internal.c
new file mode 100644
index 0000000..03362cf
--- /dev/null
+++ b/misc/win32/internal.c
@@ -0,0 +1,101 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_private.h"
+
+#include "apr_arch_misc.h"
+#include "apr_arch_file_io.h"
+#include <assert.h>
+
+/* This module is the source of -static- helper functions that are
+ * entirely internal to apr. If the fn is exported - it does not
+ * belong here.
+ *
+ * Namespace decoration is still required to protect us from symbol
+ * clashes in static linkages.
+ */
+
+
+/* Shared by apr_app.c and start.c
+ *
+ * An internal apr function to convert an array of strings (either
+ * a counted or NULL terminated list, such as an argv[argc] or env[]
+ * list respectively) from wide Unicode strings to narrow utf-8 strings.
+ * These are allocated from the MSVCRT's _CRT_BLOCK to trick the system
+ * into trusting our store.
+ */
+int apr_wastrtoastr(char const * const * *retarr,
+ wchar_t const * const *arr, int args)
+{
+ apr_size_t elesize = 0;
+ char **newarr;
+ char *elements;
+ char *ele;
+ int arg;
+
+ if (args < 0) {
+ for (args = 0; arr[args]; ++args)
+ ;
+ }
+
+ newarr = apr_malloc_dbg((args + 1) * sizeof(char *),
+ __FILE__, __LINE__);
+
+ for (arg = 0; arg < args; ++arg) {
+ newarr[arg] = (void*)(wcslen(arr[arg]) + 1);
+ elesize += (apr_size_t)newarr[arg];
+ }
+
+ /* This is a safe max allocation, we will realloc after
+ * processing and return the excess to the free store.
+ * 3 ucs bytes hold any single wchar_t value (16 bits)
+ * 4 ucs bytes will hold a wchar_t pair value (20 bits)
+ */
+ elesize = elesize * 3 + 1;
+ ele = elements = apr_malloc_dbg(elesize * sizeof(char),
+ __FILE__, __LINE__);
+
+ for (arg = 0; arg < args; ++arg) {
+ apr_size_t len = (apr_size_t)newarr[arg];
+ apr_size_t newlen = elesize;
+
+ newarr[arg] = ele;
+ (void)apr_conv_ucs2_to_utf8(arr[arg], &len,
+ newarr[arg], &elesize);
+
+ newlen -= elesize;
+ ele += newlen;
+ assert(elesize && (len == 0));
+ }
+
+ newarr[arg] = NULL;
+ *(ele++) = '\0';
+
+ /* Return to the free store if the heap realloc is the least bit optimized
+ */
+ ele = apr_realloc_dbg(elements, ele - elements,
+ __FILE__, __LINE__);
+
+ if (ele != elements) {
+ apr_size_t diff = ele - elements;
+ for (arg = 0; arg < args; ++arg) {
+ newarr[arg] += diff;
+ }
+ }
+
+ *retarr = (char const * const *)newarr;
+ return args;
+}
diff --git a/misc/win32/misc.c b/misc/win32/misc.c
new file mode 100644
index 0000000..bfb7efa
--- /dev/null
+++ b/misc/win32/misc.c
@@ -0,0 +1,266 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_private.h"
+#include "apr_arch_misc.h"
+#include "apr_arch_file_io.h"
+#include "assert.h"
+#include "apr_lib.h"
+#include "tchar.h"
+
+APR_DECLARE_DATA apr_oslevel_e apr_os_level = APR_WIN_UNK;
+
+apr_status_t apr_get_oslevel(apr_oslevel_e *level)
+{
+ if (apr_os_level == APR_WIN_UNK)
+ {
+ OSVERSIONINFOEXW oslev;
+ oslev.dwOSVersionInfoSize = sizeof(oslev);
+ if (!GetVersionExW((OSVERSIONINFOW*) &oslev)) {
+ return apr_get_os_error();
+ }
+
+ if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ unsigned int servpack = oslev.wServicePackMajor;
+
+ if (oslev.dwMajorVersion < 3) {
+ apr_os_level = APR_WIN_UNSUP;
+ }
+ else if (oslev.dwMajorVersion == 3) {
+ if (oslev.dwMajorVersion < 50) {
+ apr_os_level = APR_WIN_UNSUP;
+ }
+ else if (oslev.dwMajorVersion == 50) {
+ apr_os_level = APR_WIN_NT_3_5;
+ }
+ else {
+ apr_os_level = APR_WIN_NT_3_51;
+ }
+ }
+ else if (oslev.dwMajorVersion == 4) {
+ if (servpack < 2)
+ apr_os_level = APR_WIN_NT_4;
+ else if (servpack <= 2)
+ apr_os_level = APR_WIN_NT_4_SP2;
+ else if (servpack <= 3)
+ apr_os_level = APR_WIN_NT_4_SP3;
+ else if (servpack <= 4)
+ apr_os_level = APR_WIN_NT_4_SP4;
+ else if (servpack <= 5)
+ apr_os_level = APR_WIN_NT_4_SP5;
+ else
+ apr_os_level = APR_WIN_NT_4_SP6;
+ }
+ else if (oslev.dwMajorVersion == 5) {
+ if (oslev.dwMinorVersion == 0) {
+ if (servpack == 0)
+ apr_os_level = APR_WIN_2000;
+ else if (servpack == 1)
+ apr_os_level = APR_WIN_2000_SP1;
+ else
+ apr_os_level = APR_WIN_2000_SP2;
+ }
+ else if (oslev.dwMinorVersion == 2) {
+ apr_os_level = APR_WIN_2003;
+ }
+ else {
+ if (servpack < 1)
+ apr_os_level = APR_WIN_XP;
+ else if (servpack == 1)
+ apr_os_level = APR_WIN_XP_SP1;
+ else
+ apr_os_level = APR_WIN_XP_SP2;
+ }
+ }
+ else if (oslev.dwMajorVersion == 6) {
+ if (oslev.dwMinorVersion == 0)
+ apr_os_level = APR_WIN_VISTA;
+ else if (oslev.dwMinorVersion == 1) {
+ if (servpack < 1)
+ apr_os_level = APR_WIN_7;
+ else
+ apr_os_level = APR_WIN_7_SP1;
+ }
+ else if (oslev.dwMinorVersion == 2)
+ apr_os_level = APR_WIN_8;
+ else
+ apr_os_level = APR_WIN_8_1;
+ }
+ else {
+ apr_os_level = APR_WIN_10;
+ }
+ }
+#ifndef WINNT
+ else if (oslev.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+ TCHAR *prevision;
+ if (prevision = oslev.szCSDVersion) {
+ while (*prevision && !apr_isupper(*prevision)) {
+ prevision++;
+ }
+ }
+ else prevision = _T("");
+
+ if (oslev.dwMinorVersion < 10) {
+ if (*prevision < _T('C'))
+ apr_os_level = APR_WIN_95;
+ else
+ apr_os_level = APR_WIN_95_OSR2;
+ }
+ else if (oslev.dwMinorVersion < 90) {
+ if (*prevision < _T('A'))
+ apr_os_level = APR_WIN_98;
+ else
+ apr_os_level = APR_WIN_98_SE;
+ }
+ else {
+ apr_os_level = APR_WIN_ME;
+ }
+ }
+#endif
+#ifdef _WIN32_WCE
+ else if (oslev.dwPlatformId == VER_PLATFORM_WIN32_CE)
+ {
+ if (oslev.dwMajorVersion < 3) {
+ apr_os_level = APR_WIN_UNSUP;
+ }
+ else {
+ apr_os_level = APR_WIN_CE_3;
+ }
+ }
+#endif
+ else {
+ apr_os_level = APR_WIN_UNSUP;
+ }
+ }
+
+ *level = apr_os_level;
+
+ if (apr_os_level <= APR_WIN_UNSUP) {
+ return APR_EGENERAL;
+ }
+
+ return APR_SUCCESS;
+}
+
+
+/* This is the helper code to resolve late bound entry points
+ * missing from one or more releases of the Win32 API
+ */
+
+static const char* const lateDllName[DLL_defined] = {
+ "kernel32", "advapi32", "mswsock", "ws2_32", "shell32", "ntdll.dll",
+ "Iphplapi" };
+static HMODULE lateDllHandle[DLL_defined] = {
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL };
+
+FARPROC apr_load_dll_func(apr_dlltoken_e fnLib, char* fnName, int ordinal)
+{
+ if (!lateDllHandle[fnLib]) {
+ lateDllHandle[fnLib] = LoadLibraryA(lateDllName[fnLib]);
+ if (!lateDllHandle[fnLib])
+ return NULL;
+ }
+#if defined(_WIN32_WCE)
+ if (ordinal)
+ return GetProcAddressA(lateDllHandle[fnLib], (const char *)
+ (apr_ssize_t)ordinal);
+ else
+ return GetProcAddressA(lateDllHandle[fnLib], fnName);
+#else
+ if (ordinal)
+ return GetProcAddress(lateDllHandle[fnLib], (const char *)
+ (apr_ssize_t)ordinal);
+ else
+ return GetProcAddress(lateDllHandle[fnLib], fnName);
+#endif
+}
+
+/* Declared in include/arch/win32/apr_dbg_win32_handles.h
+ */
+APR_DECLARE_NONSTD(HANDLE) apr_dbg_log(char* fn, HANDLE ha, char* fl, int ln,
+ int nh, /* HANDLE hv, char *dsc */...)
+{
+ static DWORD tlsid = 0xFFFFFFFF;
+ static HANDLE fh = NULL;
+ static long ctr = 0;
+ static CRITICAL_SECTION cs;
+ long seq;
+ DWORD wrote;
+ char *sbuf;
+
+ seq = (InterlockedIncrement)(&ctr);
+
+ if (tlsid == 0xFFFFFFFF) {
+ tlsid = (TlsAlloc)();
+ }
+
+ sbuf = (TlsGetValue)(tlsid);
+ if (!fh || !sbuf) {
+ sbuf = (malloc)(1024);
+ (TlsSetValue)(tlsid, sbuf);
+ sbuf[1023] = '\0';
+ if (!fh) {
+ (GetModuleFileNameA)(NULL, sbuf, 250);
+ sprintf(strchr(sbuf, '\0'), ".%u",
+ (unsigned int)(GetCurrentProcessId)());
+ fh = (CreateFileA)(sbuf, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, 0, NULL);
+ (InitializeCriticalSection)(&cs);
+ }
+ }
+
+ if (!nh) {
+ (sprintf)(sbuf, "%p %08x %08x %s() %s:%d\n",
+ ha, (unsigned int)seq, (unsigned int)GetCurrentThreadId(),
+ fn, fl, ln);
+ (EnterCriticalSection)(&cs);
+ (WriteFile)(fh, sbuf, (DWORD)strlen(sbuf), &wrote, NULL);
+ (LeaveCriticalSection)(&cs);
+ }
+ else {
+ va_list a;
+ va_start(a,nh);
+ (EnterCriticalSection)(&cs);
+ do {
+ HANDLE *hv = va_arg(a, HANDLE*);
+ char *dsc = va_arg(a, char*);
+ if (strcmp(dsc, "Signaled") == 0) {
+ if ((apr_ssize_t)ha >= STATUS_WAIT_0
+ && (apr_ssize_t)ha < STATUS_ABANDONED_WAIT_0) {
+ hv += (apr_ssize_t)ha;
+ }
+ else if ((apr_ssize_t)ha >= STATUS_ABANDONED_WAIT_0
+ && (apr_ssize_t)ha < STATUS_USER_APC) {
+ hv += (apr_ssize_t)ha - STATUS_ABANDONED_WAIT_0;
+ dsc = "Abandoned";
+ }
+ else if ((apr_ssize_t)ha == WAIT_TIMEOUT) {
+ dsc = "Timed Out";
+ }
+ }
+ (sprintf)(sbuf, "%p %08x %08x %s(%s) %s:%d\n",
+ *hv, (unsigned int)seq,
+ (unsigned int)GetCurrentThreadId(),
+ fn, dsc, fl, ln);
+ (WriteFile)(fh, sbuf, (DWORD)strlen(sbuf), &wrote, NULL);
+ } while (--nh);
+ (LeaveCriticalSection)(&cs);
+ va_end(a);
+ }
+ return ha;
+}
diff --git a/misc/win32/rand.c b/misc/win32/rand.c
new file mode 100644
index 0000000..cb5a653
--- /dev/null
+++ b/misc/win32/rand.c
@@ -0,0 +1,69 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include <rpc.h>
+#include <wincrypt.h>
+#include "apr_private.h"
+#include "apr_general.h"
+#include "apr_portable.h"
+#include "apr_arch_misc.h"
+
+
+APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf,
+ apr_size_t length)
+{
+ HCRYPTPROV hProv;
+ apr_status_t res = APR_SUCCESS;
+
+ /* 0x40 bit = CRYPT_SILENT, only introduced in more recent PSDKs
+ * and will only work for Win2K and later.
+ */
+ DWORD flags = CRYPT_VERIFYCONTEXT
+ | ((apr_os_level >= APR_WIN_2000) ? 0x40 : 0);
+
+ if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, flags)) {
+ return apr_get_os_error();
+ }
+ /* XXX: An ugly hack for Win64, randomness is such that noone should
+ * ever expect > 2^31 bytes of data at once without the prng
+ * coming to a complete halt.
+ */
+ if (!CryptGenRandom(hProv, (DWORD)length, buf)) {
+ res = apr_get_os_error();
+ }
+ CryptReleaseContext(hProv, 0);
+ return res;
+}
+
+
+APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
+{
+ /* Note: this call doesn't actually require CoInitialize() first
+ *
+ * XXX: we should scramble the bytes or some such to eliminate the
+ * possible misuse/abuse since uuid is based on the NIC address, and
+ * is therefore not only a uniqifier, but an identity (which might not
+ * be appropriate in all cases.
+ *
+ * Note that Win2000, XP and later no longer suffer from this problem,
+ * a scrambling fix is only needed for (apr_os_level < APR_WIN_2000)
+ */
+ if (FAILED(UuidCreate((UUID *)uuid_data))) {
+ return APR_EGENERAL;
+ }
+ return APR_SUCCESS;
+}
diff --git a/misc/win32/start.c b/misc/win32/start.c
new file mode 100644
index 0000000..2d7b5ff
--- /dev/null
+++ b/misc/win32/start.c
@@ -0,0 +1,232 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_private.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_signal.h"
+#include "shellapi.h"
+
+#include "apr_arch_misc.h" /* for WSAHighByte / WSALowByte */
+#include "wchar.h"
+#include "apr_arch_file_io.h" /* bring in unicode-ness */
+#include "apr_arch_threadproc.h" /* bring in apr_threadproc_init */
+#include "assert.h"
+
+/* This symbol is _private_, although it must be exported.
+ */
+int APR_DECLARE_DATA apr_app_init_complete = 0;
+
+#if !defined(_WIN32_WCE)
+/* Used by apr_app_initialize to reprocess the environment
+ *
+ * An internal apr function to convert a double-null terminated set
+ * of single-null terminated strings from wide Unicode to narrow utf-8
+ * as a list of strings. These are allocated from the MSVCRT's
+ * _CRT_BLOCK to trick the system into trusting our store.
+ */
+static int warrsztoastr(const char * const * *retarr,
+ const wchar_t * arrsz)
+{
+ const apr_wchar_t *wch;
+ apr_size_t totlen;
+ apr_size_t newlen;
+ apr_size_t wsize;
+ char **env;
+ char *pstrs;
+ char *strs;
+ int arg, args;
+
+ for (args = 1, wch = arrsz; wch[0] || wch[1]; ++wch)
+ if (!*wch)
+ ++args;
+ wsize = 1 + wch - arrsz;
+
+ /* This is a safe max allocation, we will alloc each
+ * string exactly after processing and return this
+ * temporary buffer to the free store.
+ * 3 ucs bytes hold any single wchar_t value (16 bits)
+ * 4 ucs bytes will hold a wchar_t pair value (20 bits)
+ */
+ newlen = totlen = wsize * 3 + 1;
+ pstrs = strs = apr_malloc_dbg(newlen * sizeof(char),
+ __FILE__, __LINE__);
+
+ (void)apr_conv_ucs2_to_utf8(arrsz, &wsize, strs, &newlen);
+
+ assert(newlen && !wsize);
+
+ *retarr = env = apr_malloc_dbg((args + 1) * sizeof(char*),
+ __FILE__, __LINE__);
+ for (arg = 0; arg < args; ++arg) {
+ char* p = pstrs;
+ int len = 0;
+ while (*p++)
+ ++len;
+ len += 1;
+
+ *env = apr_malloc_dbg(len * sizeof(char),
+ __FILE__, __LINE__);
+ memcpy(*env, pstrs, len * sizeof(char));
+
+ pstrs += len;
+ ++env;
+ }
+
+ *env = NULL;
+ free(strs);
+
+ return args;
+}
+#endif
+
+/* Reprocess the arguments to main() for a completely apr-ized application
+ */
+
+APR_DECLARE(apr_status_t) apr_app_initialize(int *argc,
+ const char * const * *argv,
+ const char * const * *env)
+{
+ apr_status_t rv = apr_initialize();
+
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+#if defined(_WIN32_WCE)
+ apr_app_init_complete = 1;
+#elif APR_HAS_UNICODE_FS
+ IF_WIN_OS_IS_UNICODE
+ {
+ apr_wchar_t **wstrs;
+ apr_wchar_t *sysstr;
+ int wstrc;
+ int dupenv;
+
+ if (apr_app_init_complete) {
+ return rv;
+ }
+
+ apr_app_init_complete = 1;
+
+ sysstr = GetCommandLineW();
+ if (sysstr) {
+ wstrs = CommandLineToArgvW(sysstr, &wstrc);
+ if (wstrs) {
+ *argc = apr_wastrtoastr(argv, wstrs, wstrc);
+ GlobalFree(wstrs);
+ }
+ }
+
+ sysstr = GetEnvironmentStringsW();
+ dupenv = warrsztoastr(&_environ, sysstr);
+
+ if (env) {
+ *env = apr_malloc_dbg((dupenv + 1) * sizeof (char *),
+ __FILE__, __LINE__ );
+ memcpy((void*)*env, _environ, (dupenv + 1) * sizeof (char *));
+ }
+ else {
+ }
+
+ FreeEnvironmentStringsW(sysstr);
+
+ /* MSVCRT will attempt to maintain the wide environment calls
+ * on _putenv(), which is bogus if we've passed a non-ascii
+ * string to _putenv(), since they use MultiByteToWideChar
+ * and breaking the implicit utf-8 assumption we've built.
+ *
+ * Reset _wenviron for good measure.
+ */
+ if (_wenviron) {
+ apr_wchar_t **wenv = _wenviron;
+ _wenviron = NULL;
+ free(wenv);
+ }
+
+ }
+#endif
+ return rv;
+}
+
+static int initialized = 0;
+
+/* Provide to win32/thread.c */
+extern DWORD tls_apr_thread;
+
+APR_DECLARE(apr_status_t) apr_initialize(void)
+{
+ apr_pool_t *pool;
+ apr_status_t status;
+ int iVersionRequested;
+ WSADATA wsaData;
+ int err;
+ apr_oslevel_e osver;
+
+ if (initialized++) {
+ return APR_SUCCESS;
+ }
+
+ /* Initialize apr_os_level global */
+ if (apr_get_oslevel(&osver) != APR_SUCCESS) {
+ return APR_EEXIST;
+ }
+
+ tls_apr_thread = TlsAlloc();
+ if ((status = apr_pool_initialize()) != APR_SUCCESS)
+ return status;
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return APR_ENOPOOL;
+ }
+
+ apr_pool_tag(pool, "apr_initialize");
+
+ iVersionRequested = MAKEWORD(WSAHighByte, WSALowByte);
+ err = WSAStartup((WORD) iVersionRequested, &wsaData);
+ if (err) {
+ return err;
+ }
+ if (LOBYTE(wsaData.wVersion) != WSAHighByte ||
+ HIBYTE(wsaData.wVersion) != WSALowByte) {
+ WSACleanup();
+ return APR_EEXIST;
+ }
+
+ apr_signal_init(pool);
+
+ apr_threadproc_init(pool);
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE_NONSTD(void) apr_terminate(void)
+{
+ initialized--;
+ if (initialized) {
+ return;
+ }
+ apr_pool_terminate();
+
+ WSACleanup();
+
+ TlsFree(tls_apr_thread);
+}
+
+APR_DECLARE(void) apr_terminate2(void)
+{
+ apr_terminate();
+}
diff --git a/misc/win32/utf8.c b/misc/win32/utf8.c
new file mode 100644
index 0000000..280f406
--- /dev/null
+++ b/misc/win32/utf8.c
@@ -0,0 +1,259 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_private.h"
+#include "apr_errno.h"
+#include "apr_arch_utf8.h"
+
+/* Implementation of RFC 3629, "UTF-8, a transformation format of ISO 10646"
+ * with particular attention to canonical translation forms (see section 10
+ * "Security Considerations" of the RFC for more info).
+ *
+ * Since several architectures including Windows support unicode, with UCS2
+ * used as the actual storage conventions by that archicture, these functions
+ * exist to transform or validate UCS2 strings into APR's 'char' type
+ * convention. It is left up to the operating system to determine the
+ * validitity of the string, e.g. normative forms, in the context of
+ * its native language support. Other file systems which support filename
+ * characters of 0x80-0xff but have no explicit requirement for Unicode
+ * will find this function useful only for validating the character sequences
+ * and rejecting poorly encoded UTF8 sequences.
+ *
+ * Len UCS-4 range (hex) UTF-8 octet sequence (binary)
+ * 1:2 00000000-0000007F 0xxxxxxx
+ * 2:2 00000080-000007FF 110XXXXx 10xxxxxx
+ * 3:2 00000800-0000FFFF 1110XXXX 10Xxxxxx 10xxxxxx
+ * 4:4 00010000-001FFFFF 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx
+ * 00200000-03FFFFFF 111110XX 10XXXxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 04000000-7FFFFFFF 1111110X 10XXXXxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *
+ * One of the X bits must be 1 to avoid overlong representation of ucs2 values.
+ *
+ * For conversion into ucs2, the 4th form is limited in range to 0010 FFFF,
+ * and the final two forms are used only by full ucs4, per RFC 3629;
+ *
+ * "Pairs of UCS-2 values between D800 and DFFF (surrogate pairs in
+ * Unicode parlance), being actually UCS-4 characters transformed
+ * through UTF-16, need special treatment: the UTF-16 transformation
+ * must be undone, yielding a UCS-4 character that is then transformed
+ * as above."
+ *
+ * From RFC2781 UTF-16: the compressed ISO 10646 encoding bitmask
+ *
+ * U' = U - 0x10000
+ * U' = 00000000 0000yyyy yyyyyyxx xxxxxxxx
+ * W1 = 110110yy yyyyyyyy
+ * W2 = 110111xx xxxxxxxx
+ * Max U' = 0000 00001111 11111111 11111111
+ * Max U = 0000 00010000 11111111 11111111
+ *
+ * Len is the table above is a mapping of bytes used for utf8:ucs2 values,
+ * which results in these conclusions of maximum allocations;
+ *
+ * apr_conv_utf8_to_ucs2 out bytes:sizeof(in) * 1 <= Req <= sizeof(in) * 2
+ * apr_conv_ucs2_to_utf8 out words:sizeof(in) / 2 <= Req <= sizeof(in) * 3 / 2
+ */
+
+APR_DECLARE(apr_status_t) apr_conv_utf8_to_ucs2(const char *in,
+ apr_size_t *inbytes,
+ apr_wchar_t *out,
+ apr_size_t *outwords)
+{
+ apr_int64_t newch, mask;
+ apr_size_t expect, eating;
+ int ch;
+
+ while (*inbytes && *outwords)
+ {
+ ch = (unsigned char)(*in++);
+ if (!(ch & 0200)) {
+ /* US-ASCII-7 plain text
+ */
+ --*inbytes;
+ --*outwords;
+ *(out++) = ch;
+ }
+ else
+ {
+ if ((ch & 0300) != 0300) {
+ /* Multibyte Continuation is out of place
+ */
+ return APR_EINVAL;
+ }
+ else
+ {
+ /* Multibyte Sequence Lead Character
+ *
+ * Compute the expected bytes while adjusting
+ * or lead byte and leading zeros mask.
+ */
+ mask = 0340;
+ expect = 1;
+ while ((ch & mask) == mask) {
+ mask |= mask >> 1;
+ if (++expect > 3) /* (truly 5 for ucs-4) */
+ return APR_EINVAL;
+ }
+ newch = ch & ~mask;
+ eating = expect + 1;
+ if (*inbytes <= expect)
+ return APR_INCOMPLETE;
+ /* Reject values of excessive leading 0 bits
+ * utf-8 _demands_ the shortest possible byte length
+ */
+ if (expect == 1) {
+ if (!(newch & 0036))
+ return APR_EINVAL;
+ }
+ else {
+ /* Reject values of excessive leading 0 bits
+ */
+ if (!newch && !((unsigned char)*in & 0077 & (mask << 1)))
+ return APR_EINVAL;
+ if (expect == 2) {
+ /* Reject values D800-DFFF when not utf16 encoded
+ * (may not be an appropriate restriction for ucs-4)
+ */
+ if (newch == 0015 && ((unsigned char)*in & 0040))
+ return APR_EINVAL;
+ }
+ else if (expect == 3) {
+ /* Short circuit values > 110000
+ */
+ if (newch > 4)
+ return APR_EINVAL;
+ if (newch == 4 && ((unsigned char)*in & 0060))
+ return APR_EINVAL;
+ }
+ }
+ /* Where the boolean (expect > 2) is true, we will need
+ * an extra word for the output.
+ */
+ if (*outwords < (apr_size_t)(expect > 2) + 1)
+ break; /* buffer full */
+ while (expect--)
+ {
+ /* Multibyte Continuation must be legal */
+ if (((ch = (unsigned char)*(in++)) & 0300) != 0200)
+ return APR_EINVAL;
+ newch <<= 6;
+ newch |= (ch & 0077);
+ }
+ *inbytes -= eating;
+ /* newch is now a true ucs-4 character
+ *
+ * now we need to fold to ucs-2
+ */
+ if (newch < 0x10000)
+ {
+ --*outwords;
+ *(out++) = (apr_wchar_t) newch;
+ }
+ else
+ {
+ *outwords -= 2;
+ newch -= 0x10000;
+ *(out++) = (apr_wchar_t) (0xD800 | (newch >> 10));
+ *(out++) = (apr_wchar_t) (0xDC00 | (newch & 0x03FF));
+ }
+ }
+ }
+ }
+ /* Buffer full 'errors' aren't errors, the client must inspect both
+ * the inbytes and outwords values
+ */
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_conv_ucs2_to_utf8(const apr_wchar_t *in,
+ apr_size_t *inwords,
+ char *out,
+ apr_size_t *outbytes)
+{
+ apr_int64_t newch, require;
+ apr_size_t need;
+ char *invout;
+ int ch;
+
+ while (*inwords && *outbytes)
+ {
+ ch = (unsigned short)(*in++);
+ if (ch < 0x80)
+ {
+ --*inwords;
+ --*outbytes;
+ *(out++) = (unsigned char) ch;
+ }
+ else
+ {
+ if ((ch & 0xFC00) == 0xDC00) {
+ /* Invalid Leading ucs-2 Multiword Continuation Character
+ */
+ return APR_EINVAL;
+ }
+ if ((ch & 0xFC00) == 0xD800) {
+ /* Leading ucs-2 Multiword Character
+ */
+ if (*inwords < 2) {
+ /* Missing ucs-2 Multiword Continuation Character
+ */
+ return APR_INCOMPLETE;
+ }
+ if (((unsigned short)(*in) & 0xFC00) != 0xDC00) {
+ /* Invalid ucs-2 Multiword Continuation Character
+ */
+ return APR_EINVAL;
+ }
+ newch = (ch & 0x03FF) << 10 | ((unsigned short)(*in++) & 0x03FF);
+ newch += 0x10000;
+ }
+ else {
+ /* ucs-2 Single Word Character
+ */
+ newch = ch;
+ }
+ /* Determine the absolute minimum utf-8 bytes required
+ */
+ require = newch >> 11;
+ need = 1;
+ while (require)
+ require >>= 5, ++need;
+ if (need >= *outbytes)
+ break; /* Insufficient buffer */
+ *inwords -= (need > 2) + 1;
+ *outbytes -= need + 1;
+ /* Compute the utf-8 characters in last to first order,
+ * calculating the lead character length bits along the way.
+ */
+ ch = 0200;
+ out += need + 1;
+ invout = out;
+ while (need--) {
+ ch |= ch >> 1;
+ *(--invout) = (unsigned char)(0200 | (newch & 0077));
+ newch >>= 6;
+ }
+ /* Compute the lead utf-8 character and move the dest offset
+ */
+ *(--invout) = (unsigned char)(ch | newch);
+ }
+ }
+ /* Buffer full 'errors' aren't errors, the client must inspect both
+ * the inwords and outbytes values
+ */
+ return APR_SUCCESS;
+}