feat:replace boost library with C++11 std library

This commit is contained in:
Livox-SDK
2020-04-01 20:53:55 +08:00
parent 6d06233944
commit d3258bbd97
1936 changed files with 241862 additions and 60153 deletions
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
MODULE LIBC.NLM
MODULE WS2_32.NLM
EXPORT @aprlib.imp
+34
View File
@@ -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);
}
+186
View File
@@ -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;
}
+70
View File
@@ -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 */
+203
View File
@@ -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();
}
+83
View File
@@ -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);
}
+88
View File
@@ -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
}
+443
View File
@@ -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);
}
}
+309
View File
@@ -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;
}
+221
View File
@@ -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 */
+250
View File
@@ -0,0 +1,250 @@
/* 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
#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)
{
#ifdef 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_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(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();
#endif /* DEV_RANDOM */
return APR_SUCCESS;
}
#undef STR
#undef XSTR
#ifdef OS2
#include "randbyte_os2.inc"
#endif
#endif /* APR_HAS_RANDOM */
+123
View File
@@ -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();
}
+89
View File
@@ -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();
}
+35
View File
@@ -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;
}
+80
View File
@@ -0,0 +1,80 @@
/* 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 dupenv;
(void)apr_wastrtoastr(&argv, wargv, argc);
dupenv = apr_wastrtoastr(&env, wenv, -1);
_environ = apr_malloc_dbg((dupenv + 1) * sizeof (char *),
__FILE__, __LINE__ );
memcpy(_environ, env, (dupenv + 1) * sizeof (char *));
/* 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) {
wenv = _wenviron;
_wenviron = NULL;
free((wchar_t **)wenv);
}
apr_app_init_complete = 1;
return main(argc, argv, env);
}
+55
View File
@@ -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);
}
+192
View File
@@ -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
}
+101
View File
@@ -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;
}
+266
View File
@@ -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)
{
static OSVERSIONINFO oslev;
oslev.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&oslev);
if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
static unsigned int servpack = 0;
TCHAR *pservpack;
if ((pservpack = oslev.szCSDVersion)) {
while (*pservpack && !apr_isdigit(*pservpack)) {
pservpack++;
}
if (*pservpack)
#ifdef _UNICODE
servpack = _wtoi(pservpack);
#else
servpack = atoi(pservpack);
#endif
}
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
apr_os_level = APR_WIN_7;
}
else {
apr_os_level = APR_WIN_XP;
}
}
#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" };
static HMODULE lateDllHandle[DLL_defined] = {
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;
}
+69
View File
@@ -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;
}
+232
View File
@@ -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();
}
+259
View File
@@ -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;
}