#include <X11/Xmd.h>])
fi
-bsdPrintfWrappers=no
-if test "$os" = "linux"; then
- AC_CHECK_LIB([c],
- [ecvt],
- [bsdPrintfWrappers=yes],
- [])
-fi
-
###
### Typdefs, structs, and compiler quarks.
###
AM_CONDITIONAL(HAVE_GTKMM, test "$have_x" = "yes" -a \( "$with_gtkmm" = "yes" -o "$with_gtkmm3" = "yes" \) )
AM_CONDITIONAL(HAVE_PAM, test "$with_pam" = "yes")
AM_CONDITIONAL(USE_SLASH_PROC, test "$os" = "linux")
-AM_CONDITIONAL(USE_PRINTF_WRAPPERS, test "$bsdPrintfWrappers" = "yes")
AM_CONDITIONAL(ENABLE_DEPLOYPKG, test "$enable_deploypkg" = "yes")
AM_CONDITIONAL(ENABLE_GRABBITMQPROXY, test "$enable_grabbitmqproxy" = "yes")
AM_CONDITIONAL(ENABLE_VGAUTH, test "$enable_vgauth" = "yes")
FileLockAppendMessage(MsgList **msgs, // IN/OUT/OPT:
int err) // IN: errno
{
+#if defined(VMX86_TOOLS)
+ Log(LGPFX "A file locking error (%d) has occurred: %s.",
+ err, Err_Errno2String(err));
+#else
MsgList_Append(msgs, MSGID(fileLock.posix)
"A file locking error (%d) has occurred: %s.",
err, Err_Errno2String(err));
+#endif
}
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2006-2016 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * bsd_output.h --
- *
- * Declaration of BSD-borrowed formatted string output functions.
- */
-
-#ifndef _BSD_OUTPUT_H_
-#define _BSD_OUTPUT_H_
-
-#define INCLUDE_ALLOW_USERLEVEL
-#include "includeCheck.h"
-
-#include "compat/compat_stdarg.h"
-
-/*
- * Equivalents to the Windows vs*printf functions, except backed by code
- * borrowed from FreeBSD. This is necessary to provide certain
- * functionality missing from Windows formatted output APIs - namely
- * support for both positional arguments and 64-bit integers on all
- * platforms.
- *
- * Where feasible the BSD code has been altered to match what the
- * VisualC libc versions of vs*printf expect and do, as opposed to what
- * the GNU libc or FreeBSD versions do. Regarding 64-bit arguments, this
- * code supports all four of these prefixes: 'L', 'll', 'q', or 'I64'.
- */
-
-int
-bsd_vsnprintf(char **outbuf, size_t bufSize, const char *fmt0,
- va_list ap);
-
-int
-bsd_vsnprintf_c_locale(char **outbuf, size_t bufSize, const char *fmt0,
- va_list ap);
-
-int
-bsd_vsnwprintf(wchar_t **outbuf, size_t bufSize, const wchar_t *fmt0,
- va_list ap);
-
-#endif // _BSD_OUTPUT_H_
+++ /dev/null
-/* **********************************************************
- * Copyright 2008-2016 VMware, Inc. All rights reserved. -- VMware Confidential
- * **********************************************************/
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * bsdfmt.h --
- *
- * BSD-derived formatter (sprintf, etc.) support.
- *
- * Most of this code came from bsd_vsnprintf.c and bsd_output_int.h,
- * which in turn came from vfprintf.c in the FreeBSD distribution.
- * See bsd_vsnprintf.c for more details.
- */
-
-#ifndef _BSDFMT_H_
-#define _BSDFMT_H_
-
-#define INCLUDE_ALLOW_USERLEVEL
-#include "includeCheck.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#ifdef _WIN32 // {
-
-#pragma warning(disable : 4018 4047 4101 4102 4146 4244 4267)
-
-#define INTMAX_MAX MAX_INT64
-
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short u_short;
-typedef unsigned char u_char;
-typedef __int64 intmax_t;
-typedef unsigned __int64 uintmax_t;
-typedef intptr_t ptrdiff_t;
-
-#else // } {
-
-/* For u_int and u_long, and other types we might want. */
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <stddef.h>
-
-#if defined(__FreeBSD__) && __FreeBSD_version < 500029
-#define INTMAX_MAX 9223372036854775807LL
-#define UINTMAX_MAX 18446744073709551615ULL
-typedef int64 intmax_t;
-typedef uint64 uintmax_t;
-typedef int32 wint_t;
-#endif
-
-#endif // }
-
-/*
- * I/O descriptors for BSDFmt_sfvwrite().
- */
-
-typedef struct BSDFmt_IOV {
- void *iov_base;
- size_t iov_len;
-} BSDFmt_IOV;
-
-typedef struct BSDFmt_UIO {
- BSDFmt_IOV *uio_iov;
- int uio_iovcnt;
- int uio_resid;
-} BSDFmt_UIO;
-
-#define BSDFMT_NIOV 8
-
-typedef struct BSDFmt_StrBuf {
- Bool alloc;
- Bool error;
- char *buf;
- size_t size;
- size_t index;
-} BSDFmt_StrBuf;
-
-int BSDFmt_SFVWrite(BSDFmt_StrBuf *sbuf, BSDFmt_UIO *uio);
-int BSDFmt_SPrint(BSDFmt_StrBuf *sbuf, BSDFmt_UIO *uio);
-
-
-/*
- * Conversion functions
- */
-
-char *BSDFmt_WCharToUTF8(wchar_t *, int);
-char *BSDFmt_UJToA(uintmax_t, char *, int, int, const char *, int, char,
- const char *);
-
-
-/*
- * Don't use typedef for mbstate_t because it's actually defined
- * in VS2003/VC7/include/wchar.h -- edward
- */
-
-#if defined(_WIN32) && _MSC_VER < 1900
-#define mbstate_t int
-#endif
-
-
-/*
- * Macros for converting digits to letters and vice versa
- */
-
-#define to_digit(c) ((c) - '0')
-#define is_digit(c) ((unsigned)to_digit(c) <= 9)
-#define to_char(n) ((n) + '0')
-
-
-/*
- * Floating point
- */
-
-#ifndef NO_FLOATING_POINT // {
-
-#include <float.h>
-#include <math.h>
-
-#define MAXEXPDIG 6
-#define DEFPREC 6
-
-int BSDFmt_Exponent(char *, int, int);
-
-extern char *dtoa(double d, int mode, int prec, int *expOut,
- int *sign, char **strEnd);
-extern char *ldtoa(long double *ld, int mode, int prec, int *expOut,
- int *sign, char **strEnd);
-extern void freedtoa(void *mem);
-
-#endif // }
-
-
-/*
- * The size of the buffer we use as scratch space for integer
- * conversions, among other things. Technically, we would need the
- * most space for base 10 conversions with thousands' grouping
- * characters between each pair of digits. 100 bytes is a
- * conservative overestimate even for a 128-bit uintmax_t.
- */
-
-#define INT_CONV_BUF 100
-
-#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
-
-/*
- * Flags used during conversion.
- */
-
-#define ALT 0x001 /* alternate form */
-#define LADJUST 0x004 /* left adjustment */
-#define LONGINT 0x010 /* long integer */
-#define LLONGINT 0x020 /* long long integer */
-#define SHORTINT 0x040 /* short integer */
-#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
-#define FPT 0x100 /* Floating point number */
-#define GROUPING 0x200 /* use grouping ("'" flag) */
-/* C99 additional size modifiers: */
-#define SIZET 0x400 /* size_t */
-#define PTRDIFFT 0x800 /* ptrdiff_t */
-#define INTMAXT 0x1000 /* intmax_t */
-#define CHARINT 0x2000 /* print char using int format */
-
-#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
-
-
-/*
- * Choose PADSIZE to trade efficiency vs. size. If larger printf
- * fields occur frequently, increase PADSIZE and make the initialisers
- * below longer.
- */
-
-#define PADSIZE 16 /* pad chunk size */
-extern char blanks[PADSIZE];
-extern char zeroes[PADSIZE];
-
-extern const char xdigs_lower[17];
-extern const char xdigs_upper[17];
-
-#if defined(__cplusplus)
-} // extern "C"
-#endif
-
-#endif // ifndef _BSDFMT_H_
#endif
+
/*
* These platforms use bsd_vsnprintf().
* This does not mean it has bsd_vsnwprintf().
*/
+#if !defined(OPEN_VM_TOOLS)
#if (defined _WIN32 && !defined STR_NO_WIN32_LIBS) || \
(defined __linux__ && !defined __UCLIBC__) || \
defined __APPLE__
#define HAS_BSD_PRINTF 1
#endif
+#endif
/*
* And these platforms/setups use bsd_vsnwprintf()
*/
+#if !defined(OPEN_VM_TOOLS)
#if (defined _WIN32 && !defined STR_NO_WIN32_LIBS) || \
(defined __GNUC__ && (__GNUC__ < 2 \
|| (__GNUC__ == 2 \
&& __GNUC_MINOR__ < 96)))
#define HAS_BSD_WPRINTF 1
#endif
+#endif
/*
* ASCII/UTF-8 versions
libMisc_la_SOURCES += logFixed.c
libMisc_la_SOURCES += machineID.c
libMisc_la_SOURCES += miscSolaris.c
-libMisc_la_SOURCES += msgfmt.c
-libMisc_la_SOURCES += msgList.c
libMisc_la_SOURCES += posixDlopen.c
libMisc_la_SOURCES += posixPosix.c
libMisc_la_SOURCES += posixPwd.c
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * msgList.c --
- *
- * Utilities to manipulate (stateless) lists of messages.
- * See also msg.h.
- */
-
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "vmware.h"
-#include "util.h"
-#include "str.h"
-#include "err.h"
-#include "msgList.h"
-#include "dynbuf.h"
-
-#define LOGLEVEL_MODULE main
-#include "loglevel_user.h"
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgId2MsgList --
- *
- * Create a MsgList item from the input message. Does not handle arguments;
- * the caller must handle those.
- *
- * Performs any needed sanity checks as well.
- *
- * Results:
- * A newly-allocated MsgList.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static MsgList *
-MsgId2MsgList(const char *idFmt) // IN message ID and English message
-{
- MsgList *m;
- const char *idp, *strp;
-
- /* All message strings must be prefixed by the message ID. */
- ASSERT(Msg_HasMsgID(idFmt));
-
- /*
- * Find the beginning of the ID (idp) and the string (strp).
- * The string should have the correct MSG_MAGIC(...)... form.
- */
-
- idp = idFmt + MSG_MAGIC_LEN + 1;
- strp = strchr(idp, ')') + 1;
-
- m = Util_SafeMalloc(sizeof *m);
- m->format = Util_SafeStrdup(strp);
- m->next = NULL;
- m->args = NULL;
- m->numArgs = 0;
-
- if (vmx86_debug) {
- uint32 i;
- static const char *prfx[] = {
- "msg.", // bora/lib, VMX, ...
- "vob.", // Vmkernel OBservation
- "vpxa.", // VirtualCenter host agent
- "vpxd.", // VirtualCenter server
- "hostd.", // Host agent
- // Additional prefixes go here, but do not add "button."
- };
-
- for (i = 0; i < ARRAYSIZE(prfx); i++) {
- if (!Str_Strncasecmp(idp, prfx[i], strlen(prfx[i]))) {
- break;
- }
- }
- if (i >= ARRAYSIZE(prfx)) {
- Panic("%s error: Invalid msg prefix in <%s>\n", __FUNCTION__, idp);
- }
- }
-
- m->id = Util_SafeStrndup(idp, strp - idp - 1 /* ')' character */);
-
- return m;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_AppendStr --
- *
- * Create a MsgList item from the input message. The input message MUST
- * have no arguments. Do not pass in formatted messages; use MsgList_Append
- * for that. This variant is only for MSGIDs that have no format arguments.
- *
- * If the incoming list pointer reference is NULL, operate in 'silent'
- * mode: skip all work (except preconditions). Note that in silent +
- * vmx86_debug mode, this code does all work and throws away the result,
- * to make sure all messages are parseable.
- *
- * Results:
- * New item is attached to 'list' (and '*list' is updated).
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgList_AppendStr(MsgList **list, // IN reference to existing list
- const char *id) // IN message ID and English message
-{
- ASSERT(id != NULL);
-
- /* Silently upgrade system errors to real MSGIDs. */
- if (!Msg_HasMsgID(id)) {
- ASSERT(Err_String2Errno(id) != ERR_INVALID);
- /* On release builds, tolerate other messages that lack MSGIDs. */
- MsgList_Append(list, MSGID(literal) "%s", id);
- return;
- }
-
- /*
- * The MsgList_AppendStr variant does not accept format strings. This
- * check disallows some legitimate strings, but it's probably easier
- * on the msgconv parser to just disallow all format-string-like things.
- */
- ASSERT(strchr(id, '%') == NULL);
-
- /*
- * In silent mode, skip processing in release builds. Debug
- * builds can afford the speed cost to verify message is constructable.
- */
- if (list != NULL || vmx86_debug) {
- MsgList *m = MsgId2MsgList(id);
-
- if (list != NULL) {
- m->next = *list;
- *list = m;
- } else {
- /* Silent mode, but constructed as a sanity test. Clean up. */
- ASSERT(vmx86_debug);
- MsgList_Free(m);
- }
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_VAppend --
- *
- * Create a MsgList item from the message with va_list,
- * and attach it to the incoming list.
- *
- * If the incoming list pointer reference is NULL, operate in 'silent'
- * mode: skip all work (except preconditions). Note that in silent +
- * vmx86_debug mode, this code does all work and throws away the result,
- * to make sure all messages are parseable.
- *
- * Results:
- * New item is attached to 'list' (and '*list' is updated).
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgList_VAppend(MsgList **list, // IN/OUT/OPT: reference to existing list
- const char *idFmt, // IN: message ID and English message
- va_list args) // IN: args
-{
- ASSERT(idFmt != NULL);
-
- if (!Msg_HasMsgID(idFmt)) {
- ASSERT(Err_String2Errno(idFmt) != ERR_INVALID);
- /* On release builds, tolerate other messages that lack MSGIDs. */
- MsgList_Append(list, MSGID(literal) "%s", idFmt);
- return;
- }
-
- /*
- * In silent mode, skip processing in release builds. Debug
- * builds can afford the speed cost to verify message is constructable.
- */
- if (list != NULL || vmx86_debug) {
- MsgList *m = MsgId2MsgList(idFmt);
- Bool status;
- char *error;
-
- status = MsgFmt_GetArgs(m->format, args, &m->args, &m->numArgs, &error);
- if (!status) {
- Log("%s error: %s\nformat <%s>\n", __FUNCTION__, error, m->format);
- PANIC();
- }
-
- if (list != NULL) {
- m->next = *list;
- *list = m;
- } else {
- /* Silent mode, but constructed as a sanity test. Clean up. */
- ASSERT(vmx86_debug);
- MsgList_Free(m);
- }
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_Append --
- *
- * Create the MsgList item from the message with va_list.
- *
- * Results:
- * New item is prepended to 'list' (and '*list' is new item).
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgList_Append(MsgList **list, // IN/OUT/OPT: reference to existing list
- const char *idFmt, // IN: message ID and English message
- ...) // IN: args
-{
- va_list args;
-
- va_start(args, idFmt);
- MsgList_VAppend(list, idFmt, args);
- va_end(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_AppendMsgList --
- *
- * Append the 'messages' to an existing MsgList, 'list'. Memory
- * owner ship is transfered to 'list'.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgList_AppendMsgList(MsgList **list, // IN/OUT
- MsgList *messages) // IN
-{
- if (list != NULL && messages != NULL) {
- MsgList *head = messages;
- while (messages->next != NULL) {
- messages = messages->next;
- }
- messages->next = *list;
- *list = head;
- } else {
- MsgList_Free(messages);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_VCreate --
- *
- * Create the MsgList item from the message.
- *
- * Results:
- * New MsgList structure.
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-MsgList *
-MsgList_VCreate(const char *idFmt, // IN message ID and English message
- va_list args) // IN args
-{
- MsgList *ml = NULL;
-
- MsgList_VAppend(&ml, idFmt, args);
-
- return ml;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_Create --
- *
- * Create the MsgList item from the message with va_list.
- *
- * Results:
- * New MsgList structure.
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-MsgList *
-MsgList_Create(const char *idFmt, // IN message ID and English message
- ...) // IN args
-{
- MsgList *ml = NULL;
- va_list args;
-
- va_start(args, idFmt);
- MsgList_VAppend(&ml, idFmt, args);
- va_end(args);
-
- return ml;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgList_CreateStr --
- *
- * Create the MsgList item from the message with no format arguments.
- *
- * Results:
- * New MsgList structure.
- *
- * Side effects:
- * Callers are responsible to free the returned MsgList.
- *
- *-----------------------------------------------------------------------------
- */
-
-MsgList *
-MsgList_CreateStr(const char *idFmt) // IN message ID and English message
-{
- MsgList *ml = NULL;
-
- MsgList_AppendStr(&ml, idFmt);
-
- return ml;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_Copy --
- *
- * Makes a deep copy of the MsgList.
- *
- * Results:
- * Newly allocated MsgList. Use MsgList_Free() to free.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-MsgList *
-MsgList_Copy(const MsgList *src) // IN:
-{
- MsgList *result = NULL;
- MsgList **pdst = &result;
-
- while (src != NULL) {
- MsgList *dst = Util_SafeMalloc(sizeof *dst);
-
- dst->id = Util_SafeStrdup(src->id);
- dst->format = Util_SafeStrdup(src->format);
- dst->args = MsgFmt_CopyArgs(src->args, src->numArgs);
- dst->numArgs = src->numArgs;
- dst->next = NULL;
- src = src->next;
- *pdst = dst;
- pdst = &dst->next;
- }
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_Free --
- *
- * Frees the full MsgList chain.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-MsgList_Free(MsgList *messages) // IN:
-{
- MsgList *m;
- MsgList *next;
-
- for (m = messages; m != NULL; m = next) {
- free(m->format);
- free(m->id);
- MsgFmt_FreeArgs(m->args, m->numArgs);
- next = m->next;
- free(m);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_GetMsgID --
- *
- * Returns the "main" MSGID for the message stack.
- *
- * This is useful for Msg_Post, Msg_Hint, and Msg_Question,
- * all of which have the semantic that the generalized MSGID
- * is the MSGID of the last message in the stack.
- *
- * Results:
- * Returns pointer to something within the MsgList, or
- * NULL if the MsgList doesn't exist.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-const char *
-MsgList_GetMsgID(const MsgList *messages) // IN:
-{
- if (messages == NULL) {
- return NULL;
- }
- while (messages->next != NULL) {
- messages = messages->next;
- }
-
- return messages->id;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_ToEnglishString --
- *
- * Returns the English representation of a MsgList chain. Does NOT
- * localize. (Use Msg_LocalizeList to localize instead.)
- *
- * Results:
- * Allocated memory containing message. Successive messages
- * are separated by newlines.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-MsgList_ToEnglishString(const MsgList *messages) // IN:
-{
- char *result = NULL;
-
- if (messages != NULL) {
- size_t len = 0;
- char *formatted = MsgFmt_Asprintf(&len, messages->format, messages->args,
- messages->numArgs);
- const char *eol = (len > 0 && formatted != NULL &&
- formatted[len - 1] == '\n') ? "" : "\n";
- char *tail;
-
- if (messages->next != NULL) {
- tail = MsgList_ToEnglishString(messages->next);
- } else {
- tail = Util_SafeStrdup("");
- }
- result = Str_SafeAsprintf(NULL, "%s%s%s", formatted, eol, tail);
- free(formatted);
- free(tail);
- }
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_Log --
- *
- * Emits the English representation of a MsgList chain to Log().
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-MsgList_Log(const MsgList *messages) // IN:
-{
- const MsgList *m;
-
- for (m = messages; m != NULL; m = m->next) {
- size_t len = 0;
- char *formatted = MsgFmt_Asprintf(&len, m->format, m->args, m->numArgs);
-
- Log("[%s] %s%s",
- m->id, formatted,
- (len > 0 && formatted != NULL && formatted[len - 1] == '\n') ? ""
- : "\n");
- free(formatted);
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * MsgList_Present --
- *
- * Tests if the MsgList is empty.
- *
- * Results:
- * TRUE if there are appended messages; FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-MsgList_Present(const MsgList *messages) // IN:
-{
- return messages != NULL;
-}
+++ /dev/null
-/* **********************************************************
- * Copyright (C) 2007-2017 VMware, Inc. All rights reserved.
- * **********************************************************/
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * msgfmt.c --
- *
- * MsgFmt: format messages for the Msg module
- */
-
-
-#ifdef VMKERNEL
- #include "vmkernel.h"
- #include "vm_types.h"
- #include "vm_libc.h"
-#else
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <string.h>
- #if defined(__FreeBSD__)
- #include <sys/param.h>
- #endif
- #if !defined(_WIN32) && !defined(SOL9) && \
- (!defined(__FreeBSD__) || __FreeBSD_version >= 500029)
- #include <stdint.h>
- #endif
- #if !defined(__FreeBSD__) || __FreeBSD_version >= 400017
- #include <wchar.h>
- #endif
-
- #include "vmware.h"
- #include "bsdfmt.h"
- #include "err.h"
-#endif
-
-#include "msgfmt.h"
-
-#ifdef HAS_BSD_PRINTF
- #include <limits.h>
- #include <locale.h>
- #include "msgid.h"
-#endif
-
-/*
- * Older versions of FreeBSD don't have C99 support (stdint), and also
- * do not have wide character support. Re-implement the stuff we need
- * in those cases.
- */
-
-#if defined(__FreeBSD__) && __FreeBSD_version <= 320001
-static INLINE const wchar_t *
-wmemchr(const wchar_t *s, wchar_t c, size_t n)
-{
- size_t i;
- for (i = 0; i < n; i++) {
- if (s[i] == c) {
- return &s[i];
- }
- }
-
- return NULL;
-}
-
-static INLINE size_t
-wcslen(const wchar_t *s)
-{
- size_t i;
-
- for (i = 0; s[i]; i++);
-
- return i;
-}
-#endif
-
-/*
- * The vmkernel doesn't have the Str module, malloc(), or
- * some of the standard C string functions.
- * The only ones we really need are Str_Vsnprintf() and memchr().
- */
-
-#ifdef VMKERNEL // {
-
-typedef int32 wchar_t;
-typedef int32 wint_t;
-typedef int64 intmax_t;
-typedef size_t ptrdiff_t;
-
-#define STUB(t, f, a) \
- static INLINE t f a { NOT_IMPLEMENTED(); return (t) 0;}
-#define VSTUB(f, a) \
- static INLINE void f a { NOT_IMPLEMENTED(); }
-STUB(char *, Str_Vasprintf, (char **b, const char *f, va_list a))
-STUB(void *, malloc, (size_t s))
-STUB(void *, realloc, (void *p, size_t s))
-STUB(wchar_t *, wmemchr, (const wchar_t *s, wchar_t c, size_t n))
-STUB(size_t, wcslen, (const wchar_t *s))
-STUB(char *, strdup, (const char *s))
-VSTUB(free, (void *p))
-#undef STUB
-#undef VSTUB
-
-typedef int Err_Number;
-#define ERR_INVALID (-1)
-static INLINE Err_Number
-Err_String2Errno(const char *string)
-{
- return ERR_INVALID;
-}
-
-#ifdef VMX86_DEBUG
-static INLINE Err_Number
-Err_String2ErrnoDebug(const char *string)
-{
- return ERR_INVALID;
-}
-#endif
-
-static INLINE int
-Str_Vsnprintf(char *str, size_t size, const char *format, va_list ap) {
- int n = vsnprintf(str, size, format, ap);
- ASSERT(n >= 0);
- if (n >= size) {
- str[size - 1] = '\0';
- n = -1;
- }
- return n;
-}
-
-static INLINE const void *
-memchr(const void *s, int c, size_t n)
-{
- const uint8 *p = s;
- const uint8 *e = p + n;
- while (p < e) {
- if (*p == c) {
- return p;
- }
- ++p;
- }
- return NULL;
-}
-
-#endif // }
-
-#if defined __ANDROID__
-/*
- * Android doesn't support dtoa().
- */
-#define NO_DTOA
-#endif
-
-
-/*
- * Local data
- */
-
-typedef struct MsgFmtParseState {
- MsgFmt_Arg *args;
- int numArgs;
- int maxArgs;
- char *error;
-
- /*
- * Allocator state for caller-supplied buffer.
- */
-
- void *buf;
- char *bufp;
- char *bufe;
-} MsgFmtParseState;
-
-/* d, i, o, u, x, X, e, E, f, F, g, G, a, A, c, s, C, S, p, and n --hpreg */
-static int const isSpecifier[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1,
- 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-
-/*
- * Local functions
- */
-
-static MsgFmt_SpecFunc MsgFmtGetArg1;
-static int MsgFmtAToI(char const **start, char const *end);
-static void MsgFmtError(MsgFmtParseState *state, const char *fmt, ...);
-
-static void MsgFmtAllocInit(MsgFmtParseState *state, void *buf, size_t size);
-static void *MsgFmtAlloc(MsgFmtParseState *state, size_t size);
-static Bool MsgFmtAllocArgs(MsgFmtParseState *state, int n);
-static char *MsgFmtVasprintf(MsgFmtParseState *state,
- const char *fmt, va_list args);
-static void MsgFmtFreeAll(MsgFmtParseState *state);
-static size_t MsgFmtBufUsed(MsgFmtParseState *state);
-#ifdef HAS_BSD_PRINTF
-static int MsgFmtSnprintfWork(char **outbuf, size_t bufSize, const char *fmt0,
- const struct MsgFmt_Arg *args, int numArgs);
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_ParseWin32 --
- *
- * Convert the Win32 representation of a format string into another
- * representation --hpreg
- *
- * XXX I haven't implemented %0 and %n, because they suck:
- * . they mix content and presentation
- * . they have nothing to do with parameters and hence have no
- * equivalent in other systems
- *
- * Results:
- * 0 on success
- * -1 on failure: out of memory
- * -2 on failure: invalid 'in'
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_ParseWin32(MsgFmt_LitFunc *litFunc, // IN
- MsgFmt_SpecFunc *specFunc, // IN
- void *clientData, // IN
- char const *in) // IN
-{
- char const *startUnescaped;
- unsigned int sm;
- char const *pos = 0 /* Compiler warning --hpreg */;
- char const *type = 0 /* Compiler warning --hpreg */;
- int status;
-
- startUnescaped = in;
- sm = 0;
-
- for (; *in != '\0'; in++) {
- /* Unsigned does matter --hpreg */
- unsigned char ubyte;
-
- ubyte = *in;
- switch (sm) {
- case 2: /* Found %<1-9>...<byte> --hpreg */
- if (ubyte >= '0' && ubyte <= '9') {
- break;
- }
- if (ubyte == '!') {
- type = in + 1;
- sm = 3;
- break;
- }
- if ((status = (*litFunc)(clientData, startUnescaped,
- pos - 1 - startUnescaped)) < 0 ||
- (status = (*specFunc)(clientData, pos, in - pos, "s", 1)) < 0) {
- return status;
- }
- startUnescaped = in;
- sm = 0;
- /* Fall through --hpreg */
-
- case 0: /* Found <byte> --hpreg */
- if (ubyte == '%') {
- pos = in + 1;
- sm = 1;
- }
- break;
-
- case 1: /* Found %<byte> --hpreg */
- if (ubyte >= '1' && ubyte <= '9') {
- sm = 2;
- } else {
- VERIFY(ubyte != '0' && ubyte != 'n');
- status = (*litFunc)(clientData, startUnescaped,
- in - 1 - startUnescaped);
- if (status < 0) {
- return status;
- }
- startUnescaped = in;
- sm = 0;
- }
- break;
-
- case 3: /* Found %<1-9>...!...<byte> --hpreg */
- if (ubyte == '!') {
- if ( (status = (*litFunc)(clientData, startUnescaped,
- pos - 1 - startUnescaped)) < 0
- || (status = (*specFunc)(clientData, pos, type - 1 - pos,
- type, in - type)) < 0) {
- return status;
- }
- startUnescaped = in + 1;
- sm = 0;
- }
- break;
-
- default:
- NOT_IMPLEMENTED();
- break;
- }
- }
-
- switch (sm) {
- case 0:
- status = (*litFunc)(clientData, startUnescaped, in - startUnescaped);
- if (status < 0) {
- return status;
- }
- break;
-
- case 2:
- if ( (status = (*litFunc)(clientData, startUnescaped,
- pos - 1 - startUnescaped)) < 0
- || (status = (*specFunc)(clientData, pos, in - pos, "s", 1)) < 0) {
- return status;
- }
- break;
-
- case 1:
- case 3:
- return -2;
- break;
-
- default:
- NOT_IMPLEMENTED();
- break;
- }
-
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_Parse --
- *
- * Parse a message format.
- *
- * Results:
- * 0 on success
- * -1 on failure: out of memory
- * -2 on failure: invalid 'in'
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_Parse(MsgFmt_LitFunc *litFunc, // IN
- MsgFmt_SpecFunc *specFunc, // IN
- void *clientData, // IN
- char const *in) // IN
-{
- char const *startUnescaped;
- unsigned int sm;
- unsigned int counter;
- int status;
- char const *startEscaped = 0 /* Compiler warning --hpreg */;
- char const *type = 0 /* Compiler warning --hpreg */;
- Bool usePos = FALSE /* Compiler warning --hpreg */;
-
- startUnescaped = in;
- sm = 0;
- counter = 0;
-
- for (; *in != '\0'; in++) {
- /* Unsigned does matter --hpreg */
- unsigned char ubyte;
-
- ubyte = *in;
- switch (sm) {
- case 0: /* Found <byte> --hpreg */
- if (ubyte == '%') {
- sm = 1;
- }
- break;
-
- case 1: /* Found %<byte> --hpreg */
- if (ubyte == '%') {
- if (litFunc != NULL &&
- (status = (*litFunc)(clientData, startUnescaped,
- in - 1 - startUnescaped)) < 0) {
- return status;
- }
- startUnescaped = in;
- sm = 0;
- break;
- }
- startEscaped = in;
- type = in;
- if (ubyte >= '1' && ubyte <= '9') {
- sm = 2;
- break;
- }
- sm = 3;
- /* Fall through --hpreg */
-
- case 3: /* Found %<1-9>...$...<byte> or %...<byte> --hpreg */
- variant3:
- if (isSpecifier[ubyte]) {
- char const *pos;
- char const *posEnd;
- char posBuf[10 /* 32 bits unsigned in decimal --hpreg */];
-
- if (counter) {
- if (usePos != (startEscaped != type)) {
- return -2;
- }
- } else {
- usePos = (startEscaped != type);
- }
- counter++;
-
- if (usePos) {
- pos = startEscaped;
- posEnd = type - 1;
- } else {
- char *current;
- unsigned int value;
-
- current = posBuf + sizeof(posBuf);
- posEnd = current;
- value = counter;
- ASSERT(value);
- do {
- current--;
- ASSERT(current >= posBuf);
- *current = '0' + value % 10;
- value /= 10;
- } while (value);
- pos = current;
- }
-
- if (litFunc != NULL &&
- (status = (*litFunc)(clientData, startUnescaped,
- startEscaped - 1 - startUnescaped)) < 0) {
- return status;
- }
- if ((status = (*specFunc)(clientData, pos, posEnd - pos, type,
- in + 1 - type)) < 0) {
- return status;
- }
- startUnescaped = in + 1;
- sm = 0;
- break;
- }
- /* Digits for field width & precision, zero for leading zeroes,
- and dot for separator between width and precision. */
- if ((ubyte >= '0' && ubyte <= '9') || ubyte == '.') {
- break;
- }
- /* Flags */
- if (ubyte == '#' || ubyte == '-' || ubyte == ' ' || ubyte == '+' ||
- ubyte == '\'') {
- break;
- }
- /* Length modifiers */
- if (ubyte == 'L' || ubyte == 'l' || ubyte == 'h' || ubyte == 'z' ||
- ubyte == 'Z' || ubyte == 't' || ubyte == 'q' || ubyte == 'j' ||
- ubyte == 'I') {
- break;
- }
- return -2;
-
- case 2: /* Found %<1-9>...<byte> --hpreg */
- if (ubyte >= '0' && ubyte <= '9') {
- break;
- }
- if (ubyte == '$') {
- type = in + 1;
- sm = 3;
- break;
- }
- sm = 3;
- goto variant3;
-
- default:
- NOT_IMPLEMENTED();
- break;
- }
- }
-
- if (sm) {
- return -2;
- }
- if (litFunc != NULL &&
- (status = (*litFunc)(clientData, startUnescaped,
- in - startUnescaped)) < 0) {
- return status;
- }
-
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_ParseSpec --
- *
- * Given a format specifier (the % stuff), return its contituent parts.
- *
- * Results:
- * 0 on success, -2 (bad format) on failure.
- * Out parameters:
- * Width and precision are -1 if not specified.
- * Length modifier is '\0' if not specified.
- * Length modifier of "ll", "I64", or "q" is returned as 'L'.
- * (This means we freely allow %llf and %qf, which is not strictly
- * correct. However, glibc printf allows them (as well as %Ld),
- * and they mean the same thing.)
- * Length modifier of "hh" is returned as 'H'.
- * Length modifier of "Z" is returned as 'z', for compatibility
- * with old glibc.
- * On failure, some or all of the out parameters may be modified
- * in an undefined manner.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_ParseSpec(char const *pos, // IN: n$ location
- unsigned int posSize, // IN: n$ length
- char const *type, // IN: specifier after position
- unsigned int typeSize, // IN: size of above
- int *position, // OUT: argument position
- int *flags, // OUT: flags
- int *width, // OUT: width
- int *precision, // OUT: precision
- char *lengthMod, // OUT: length modifier
- char *conversion) // OUT: conversion specifier
-{
- char const *p = type;
- char const *end = type + typeSize;
-
- /*
- * Convert argument position to int.
- * Fail if not a good decimal number greater than 0.
- */
-
- {
- char const *posEnd = pos + posSize;
- *position = MsgFmtAToI(&pos, posEnd);
- if (*position <= 0 || pos != posEnd) {
- return -2;
- }
- }
-
- /*
- * The format specifier is, in this order,
- * zero or more flags
- * an optional width (a decimal number or *)
- * an optional precision (. followed by optional decimal number or *)
- * an optional length modifier (l, L, ll, z, etc.)
- * conversion specifier (a character)
- *
- * The rest of this module does not recognize * as width or precision,
- * so we don't do it here either.
- *
- * glibc 2.2 supports the I flag, which we don't. Instead, we
- * support the I, I32, and I64 length modifiers used by Microsoft.
- */
-
- /*
- * Flags
- */
-
- *flags = 0;
- for (; p < end; p++) {
- switch (*p) {
- case '#':
- *flags |= MSGFMT_FLAG_ALT;
- continue;
- case '0':
- *flags |= MSGFMT_FLAG_ZERO;
- continue;
- case '-':
- *flags |= MSGFMT_FLAG_MINUS;
- continue;
- case ' ':
- *flags |= MSGFMT_FLAG_SPACE;
- continue;
- case '+':
- *flags |= MSGFMT_FLAG_PLUS;
- continue;
- case '\'':
- *flags |= MSGFMT_FLAG_QUOTE;
- continue;
-
- default:
- break;
- }
- break;
- }
-
- /*
- * Width
- */
-
- if (p >= end || *p < '1' || *p > '9') {
- *width = -1;
- } else {
- *width = MsgFmtAToI(&p, end);
- if (*width < 0) {
- return -2;
- }
- }
-
- /*
- * Precision
- */
-
- if (p >= end || *p != '.') {
- *precision = -1;
- } else {
- p++;
- *precision = MsgFmtAToI(&p, end);
- if (*precision < 0) {
- return -2;
- }
- }
-
- /*
- * Length modifier
- */
-
- if (p >= end) {
- return -2;
- }
- *lengthMod = '\0';
- switch (*p) {
- case 'h':
- p++;
- if (p >= end || *p != 'h') {
- *lengthMod = 'h';
- } else {
- p++;
- *lengthMod = 'H';
- }
- break;
- case 'l':
- p++;
- if (p >= end || *p != 'l') {
- *lengthMod = 'l';
- } else {
- p++;
- *lengthMod = 'L';
- }
- break;
- case 'I':
- /*
- * Microsoft:
- * I64 is 64-bit number. For us, the same as L.
- * I32 is 32-bit number. For us, nothing.
- * I is size_t.
- */
- if (p + 2 < end && p[1] == '6' && p[2] == '4') {
- p += 3;
- *lengthMod = 'L';
- } else if (p + 2 < end && p[1] == '3' && p[2] == '2') {
- p += 3;
- } else {
- p++;
- *lengthMod = 'z';
- }
- break;
- case 'q':
- p++;
- *lengthMod = 'L';
- break;
- case 'Z':
- p++;
- *lengthMod = 'z';
- break;
- case 'L':
- case 'j':
- case 'z':
- case 't':
- *lengthMod = *p++;
- break;
- }
-
- /*
- * Conversion specifier
- *
- * Return false if no conversion specifier or not the last character.
- */
-
- if (p + 1 == end && isSpecifier[(unsigned char) *p]) {
- *conversion = *p;
- return 0;
- }
- return -2;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtAToI --
- *
- * Convert numeric string to integer.
- * The range is 0 to MAX_INT32 (nonnegative 32-bit signed int).
- * Empty string or a string that does not begin with
- * a digit is treated as 0.
- *
- * Results:
- * The number or -1 on overflow.
- * Start pointer updated to point to first nonnumeric character.
- * or first character before overflow.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-MsgFmtAToI(char const **start, // IN/OUT: string pointer
- char const *end) // IN: end of string
-{
- char const *p;
- int n = 0;
-
- ASSERT_ON_COMPILE(sizeof (int) >= 4);
- for (p = *start; p < end && *p >= '0' && *p <= '9'; p++) {
- if (n > MAX_INT32 / 10) {
- n = -1;
- break;
- }
- n *= 10;
- n += *p - '0';
- if (n < 0) {
- n = -1;
- break;
- }
- }
- *start = p;
- return n;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_GetArgs --
- *
- * Parse a format string and return the arguments implied by it.
- *
- * Results:
- * TRUE on sucess.
- * Out parameters:
- * The array of MsgFmt_Arg structures.
- * The number of arguments.
- * An error string on failure.
- *
- * Side effects:
- * Memory is allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MsgFmt_GetArgs(const char *fmt, // IN: format string
- va_list va, // IN: the argument list
- MsgFmt_Arg **args, // OUT: the returned arguments
- int *numArgs, // OUT: number of returned arguments
- char **error) // OUT: error string
-{
- return MsgFmt_GetArgsWithBuf(fmt, va, args, numArgs, error, NULL, NULL);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_GetArgsWithBuf --
- *
- * Parse a format string and return the arguments implied by it.
- *
- * If buf is supplied, allocate memory there instead of with malloc().
- *
- * Results:
- * TRUE on sucess.
- * Out parameters:
- * The array of MsgFmt_Arg structures.
- * The number of arguments.
- * An error string on failure.
- * The amount of buf used (if caller supplied buf)
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MsgFmt_GetArgsWithBuf(const char *fmt, // IN: format string
- va_list va, // IN: the argument list
- MsgFmt_Arg **args, // OUT: the returned arguments
- int *numArgs, // OUT: number of returned arguments
- char **error, // OUT: error string
- void *buf, // OUT: memory to store output
- size_t *bufSize) // IN/OUT: size of buf /
- // amount of buf used
-{
- MsgFmtParseState state;
- int status;
- int i;
-
- memset(&state, 0, sizeof state);
- if (buf != NULL) {
- ASSERT(bufSize != NULL);
- MsgFmtAllocInit(&state, buf, *bufSize);
- }
-
- /*
- * First pass: parse format to get argument information
- */
-
- status = MsgFmt_Parse(NULL, MsgFmtGetArg1, &state, fmt);
- if (status < 0) {
- goto bad;
- }
-
- /*
- * Second pass: get argument values
- *
- * While we can store most values directly in the MsgFmt_Arg
- * structure, strings have to be copied into allocated space.
- * When precision is specified (see comment about it in
- * MsgFmtGetArg1()), we copy at most that many bytes because
- * that's how many printf() looks at, and we must not touch
- * memory beyond what printf() would.
- */
-
- for (i = 0; i < state.numArgs; i++) {
- MsgFmt_Arg *a = state.args + i;
- switch (a->type) {
- case MSGFMT_ARG_INVALID:
- MsgFmtError(&state, "MsgFmt_GetArgs: gap in arguments at position %d",
- i + 1);
- goto bad;
- break;
-
- case MSGFMT_ARG_INT32:
- ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
- a->v.signed32 = va_arg(va, int);
- break;
- case MSGFMT_ARG_INT64:
- ASSERT_ON_COMPILE(sizeof (long long) == sizeof (int64));
- a->v.signed64 = va_arg(va, long long);
- break;
-
- case MSGFMT_ARG_PTR32:
- // we can only handle this case if native pointer is 4 bytes
- ASSERT(sizeof (void *) == sizeof (uint32));
- a->v.unsigned32 = (uint32) (uintptr_t) va_arg(va, void *);
- break;
- case MSGFMT_ARG_PTR64:
- // we can only handle this case if native pointer is 8 bytes
- ASSERT(sizeof (void *) == sizeof (uint64));
- a->v.unsigned64 = (uint64) (uintptr_t) va_arg(va, void *);
- break;
-
-#ifndef NO_FLOATING_POINT
- case MSGFMT_ARG_FLOAT64:
- ASSERT_ON_COMPILE(sizeof (double) == 8);
- a->v.float64 = va_arg(va, double);
- break;
-#endif
-
- case MSGFMT_ARG_STRING8: {
- const char *p = va_arg(va, char *);
- size_t n;
- Err_Number errorNumber;
- ASSERT_ON_COMPILE(sizeof (char) == sizeof (int8));
- ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string8) ==
- offsetof(MsgFmt_Arg, v.ptr));
- if (p == NULL) {
- a->v.string8 = NULL;
- } else {
- if (a->p.precision < 0) {
- n = strlen(p);
- } else {
- const char *q;
- n = a->p.precision;
- q = memchr(p, '\0', n);
- if (q != NULL) {
- n = q - p;
- }
- }
- // yes, sizeof (int8) is 1.
- a->v.string8 = MsgFmtAlloc(&state, n + 1);
- if (a->v.string8 == NULL) {
- status = -1;
- goto bad;
- }
- memcpy(a->v.string8, p, n);
- a->v.string8[n] = '\0';
- }
- errorNumber = Err_String2Errno(p);
-#ifdef VMX86_DEBUG
- if (errorNumber == ERR_INVALID && p != NULL) {
- // p may not be null terminated, so use string8
- errorNumber = Err_String2ErrnoDebug(a->v.string8char);
- if (errorNumber != ERR_INVALID) {
- // Err_String2ErrnoDebug already logged its info
- Log("%s: failed to look up copied error string at %p.\n",
- __FUNCTION__, p);
- }
- }
-#endif
- if (errorNumber != ERR_INVALID &&
- MSGFMT_CURRENT_PLATFORM != MSGFMT_PLATFORM_UNKNOWN) {
- ASSERT_ON_COMPILE(sizeof errorNumber == sizeof a->e.number);
- a->type = MSGFMT_ARG_ERRNO;
- a->e.platform = MSGFMT_CURRENT_PLATFORM;
- a->e.number = errorNumber;
- break;
- }
- break;
- }
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32: {
- // we can only handle the case when native wchar_t matches
- // the string char size
- const wchar_t *p = va_arg(va, wchar_t *);
- size_t n;
- ASSERT(a->type == MSGFMT_ARG_STRING16 ?
- sizeof (wchar_t) == sizeof (int16) :
- sizeof (wchar_t) == sizeof (int32));
- ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string16) ==
- offsetof(MsgFmt_Arg, v.ptr));
- ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string32) ==
- offsetof(MsgFmt_Arg, v.ptr));
- if (p == NULL) {
- a->v.ptr = NULL;
- } else {
- if (a->p.precision < 0) {
- n = wcslen(p);
- } else {
- const wchar_t *q;
- n = a->p.precision;
- q = wmemchr(p, 0, n);
- if (q != NULL) {
- n = q - p;
- }
- }
- a->v.ptr = MsgFmtAlloc(&state, sizeof (wchar_t) * (n + 1));
- if (a->v.ptr == NULL) {
- status = -1;
- goto bad;
- }
- memcpy(a->v.ptr, p, sizeof (wchar_t) * n);
- ((wchar_t *) a->v.ptr)[n] = 0;
- }
- break;
- }
-
- case MSGFMT_ARG_ERRNO: // there shouldn't be this case here
- default:
- NOT_REACHED();
- }
-
- // clear private data
- memset(&a->p, 0, sizeof a->p);
- }
-
- /*
- * Pass results back
- */
-
- if (args == NULL) {
- MsgFmtFreeAll(&state);
- } else {
- *args = state.args;
- }
- if (numArgs != NULL) {
- *numArgs = state.numArgs;
- }
- if (bufSize != NULL) {
- *bufSize = MsgFmtBufUsed(&state);
- }
- ASSERT(state.error == NULL);
- *error = NULL;
- return TRUE;
-
-bad:
- if (state.error == NULL) {
- switch (status) {
- case -1:
- MsgFmtError(&state, "MsgFmt_GetArgs: out of memory");
- break;
- case -2:
- MsgFmtError(&state, "MsgFmt_GetArgs: error in format string");
- break;
- default:
- MsgFmtError(&state, "MsgFmt_GetArgs: error %d", status);
- }
- }
- ASSERT(state.args == NULL); // MsgFmtError() frees args
- *error = state.error;
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtGetArg1 --
- *
- * Process one format specifier for MsgFmt_GetArgs().
- * Called by MsgFmt_Parse().
- *
- * Results:
- * 0 on success,
- * negative status on failure (see MsgFmt_Parse()).
- * error string in state.error on failure.
- *
- * Side effects:
- * Memory is allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-MsgFmtGetArg1(void *clientData, // IN: state
- const char *pos, // IN: n$ location
- unsigned int posSize, // IN: n$ length
- char const *type, // IN: specifier after position
- unsigned int typeSize) // IN: size of above
-{
- MsgFmtParseState *state = clientData;
- MsgFmt_Arg *a;
- int position;
- int flags;
- int width;
- int precision;
- char lengthMod;
- char conversion;
- MsgFmt_ArgType argType = MSGFMT_ARG_INVALID;
- int status;
-
- /*
- * Parse format specifier
- */
-
- status = MsgFmt_ParseSpec(pos, posSize, type, typeSize,
- &position, &flags, &width, &precision,
- &lengthMod, &conversion);
- if (status < 0) {
- MsgFmtError(state,
- "MsgFmtGetArg1: bad specifier, "
- "status %d, pos \"%.*s\", type \"%.*s\"",
- status, posSize, pos, typeSize, type);
- return status;
- }
-
- /*
- * Make room in argument array if necessary.
- */
-
- if (position > state->numArgs) {
- if (!MsgFmtAllocArgs(state, position)) {
- MsgFmtError(state, "MsgFmtGetArg1: out of memory at arg %d",
- position);
- return -1;
- }
- state->numArgs = position;
- }
-
- /*
- * Fill in argument structure based on the format specifier.
- *
- * For strings, the precision argument is the maximum length
- * to print. We need to keep track of it so MsgFmt_GetArgs()
- * can know how many characters to squirrel away, in case
- * the string isn't null terminated, is very long, or falls off
- * the end of the world.
- *
- * In all other cases, the precision is unimportant to us
- * and we don't keep it around.
- */
-
- a = state->args + position - 1;
-
- switch (conversion) {
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- switch (lengthMod) {
- // all of these take an int argument, they just print differently
- case '\0':
- case 'h':
- case 'H':
- ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
- argType = MSGFMT_ARG_INT32;
- break;
-
- case 'l':
- ASSERT_ON_COMPILE(sizeof (long) == sizeof (int32) ||
- sizeof (long) == sizeof (int64));
- if (sizeof (long) == sizeof (int32)) {
- argType = MSGFMT_ARG_INT32;
- } else {
- argType = MSGFMT_ARG_INT64;
- }
- break;
-
- case 'j':
-#ifndef _WIN32 // no intmax_t, bsd_vsnprintf() uses 64 bits
- ASSERT_ON_COMPILE(sizeof (intmax_t) == sizeof (int64));
-#endif
- case 'L':
- ASSERT_ON_COMPILE(sizeof (long long) == sizeof (int64));
- argType = MSGFMT_ARG_INT64;
- break;
-
- case 't':
- ASSERT_ON_COMPILE(sizeof (ptrdiff_t) == sizeof (size_t));
- case 'z':
- ASSERT_ON_COMPILE(sizeof (size_t) == sizeof (int32) ||
- sizeof (size_t) == sizeof (int64));
- if (sizeof (size_t) == sizeof (int32)) {
- argType = MSGFMT_ARG_INT32;
- } else {
- argType = MSGFMT_ARG_INT64;
- }
- break;
- default:
- NOT_REACHED();
- }
- break;
-
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
-#ifndef NO_FLOATING_POINT
- switch (lengthMod) {
- // l h hh t z are not defined by man page, but allowed by glibc
- case '\0':
- case 'l':
- case 'h':
- case 'H':
- case 't':
- case 'z':
- ASSERT_ON_COMPILE(sizeof (double) == 8);
- argType = MSGFMT_ARG_FLOAT64;
- break;
- // j is not defined by man page, but allowed by glibc
- case 'L':
- case 'j':
- /*
- * We don't do %Lf because it's not that useful to us, and
- * long double has a number of implementations. For example,
- * on Win32 it's the same as double, and it would have a hard
- * time dealing with a bigger one passed to it.
- * We can just coerce it down to a double at the source,
- * but then why bother?
- */
- MsgFmtError(state,
- "MsgFmtGetArg1: %%%c%c not supported, "
- "pos \"%.*s\", type \"%.*s\"",
- lengthMod, conversion, posSize, pos, typeSize, type);
- return -2;
- default:
- NOT_REACHED();
- }
- break;
-#else
- MsgFmtError(state,
- "MsgFmtGetArg1: %%%c%c not supported, "
- "pos \"%.*s\", type \"%.*s\"",
- lengthMod, conversion, posSize, pos, typeSize, type);
- return -2;
-#endif /*! NO_FLOATING_POINT */
-
- case 'c':
- switch (lengthMod) {
- // h hh t z not defined by man page, but allowed by glibc
- case '\0':
- case 'h':
- case 'H':
- case 't':
- case 'z':
- ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
- argType = MSGFMT_ARG_INT32;
- break;
- // j ll L not defined by man page nor actually supported
- case 'l':
- case 'j':
- case 'L':
- goto caseC;
- default:
- NOT_REACHED();
- }
- break;
-
- case 'C':
- caseC:
- // man page says it's a wint_t argument, but we assume promotion to int
- ASSERT_ON_COMPILE(sizeof (wint_t) <= sizeof (int) &&
- sizeof (int) == sizeof (int32));
- argType = MSGFMT_ARG_INT32;
- break;
-
- case 's':
- // we interpret the length modifier like we do for %c
- switch (lengthMod) {
- case '\0':
- case 'h':
- case 'H':
- case 't':
- case 'z':
- ASSERT_ON_COMPILE(sizeof (char) == sizeof (int8));
- argType = MSGFMT_ARG_STRING8;
- break;
- case 'l':
- case 'j':
- case 'L':
- goto caseS;
- default:
- NOT_REACHED();
- }
- // keep track of maximum string length, see block comment above
- a->p.precision = precision;
- ASSERT(a->v.ptr == NULL);
- break;
-
- case 'S':
- caseS:
-
-#if defined __ANDROID__
- ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
- sizeof (wchar_t) == sizeof (int32) ||
- sizeof (wchar_t) == sizeof (int8));
-#else
- ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
- sizeof (wchar_t) == sizeof (int32));
-#endif
-
- if (sizeof (wchar_t) == sizeof (int16)) {
- argType = MSGFMT_ARG_STRING16;
-#if defined __ANDROID__
- } else if (sizeof (wchar_t) == sizeof (int8)) {
- argType = MSGFMT_ARG_STRING8;
-#endif
- } else {
- argType = MSGFMT_ARG_STRING32;
- }
- // keep track of maximum string length, see block comment above
- a->p.precision = precision;
- ASSERT(a->v.ptr == NULL);
- break;
-
- case 'p':
- ASSERT_ON_COMPILE(sizeof (void *) == sizeof (int32) ||
- sizeof (void *) == sizeof (int64));
- if (sizeof (void *) == sizeof (int32)) {
- argType = MSGFMT_ARG_PTR32;
- } else {
- argType = MSGFMT_ARG_PTR64;
- }
- break;
-
- case 'n':
- MsgFmtError(state,
- "MsgFmtGetArg1: %%n not supported, "
- "pos \"%.*s\", type \"%.*s\"",
- posSize, pos, typeSize, type);
- return -2;
-
- // MsgFmt_ParseSpec() doesn't do %m, and we don't see %%
- default:
- MsgFmtError(state,
- "MsgFmtGetArg1: %%%c not understood, "
- "pos \"%.*s\", type \"%.*s\"",
- conversion, posSize, pos, typeSize, type);
- NOT_REACHED();
- }
-
- ASSERT(argType != MSGFMT_ARG_INVALID);
- if (a->type != MSGFMT_ARG_INVALID && a->type != argType) {
- MsgFmtError(state,
- "MsgFmtGetArg1: incompatible specifiers for argument %d, "
- "old type %d, new type %d, pos \"%.*s\", type \"%.*s\"",
- position, a->type, argType, posSize, pos, typeSize, type);
- return -2;
- }
- a->type = argType;
-
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtError --
- *
- * Format an error string and squirrel it away.
- *
- * Results:
- * Error string returned in state variable.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-MsgFmtError(MsgFmtParseState *state, // IN/OUT: state structure
- const char *fmt, // IN: error format
- ...) // IN: error args
-{
- va_list args;
-
- ASSERT(state->error == NULL);
- // free up space (in call-supplied buffer) for error string
- MsgFmtFreeAll(state);
- va_start(args, fmt);
- state->error = MsgFmtVasprintf(state, fmt, args);
- va_end(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_FreeArgs --
- *
- * Free an array of MsgFmt_Arg structures.
- * Do not call this on an array in a caller-supplied
- * buffer from MsgFmt_GetArgsWithBuf().
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgFmt_FreeArgs(MsgFmt_Arg *args, // IN/OUT: arguments to free
- int numArgs) // IN: number of arguments
-{
- int i;
-
- for (i = 0; i < numArgs; i++) {
- switch (args[i].type) {
- case MSGFMT_ARG_STRING8:
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32:
- case MSGFMT_ARG_ERRNO:
- free(args[i].v.ptr);
- break;
- default:
- ;
- }
- }
- free(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtAllocInit --
- *
- * Initialize allocator for caller-supplied buffer.
- *
- * Results:
- * None.
- *
- * Side effects:
- * As described.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-MsgFmtAllocInit(MsgFmtParseState *state, // IN/OUT: state structure
- void *buf, // IN: buffer
- size_t size) // IN: size to allocate
-{
- state->bufp = state->buf = buf;
- state->bufe = state->bufp + size;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtAlloc --
- *
- * Allocate memory from malloc() or from supplied buffer.
- *
- * Results:
- * Pointer or NULL on failure.
- *
- * Side effects:
- * Memory allocated or state updated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void *
-MsgFmtAlloc(MsgFmtParseState *state, // IN/OUT: state structure
- size_t size) // IN: size to allocate
-{
- void *p;
-
- if (state->buf == NULL) {
- p = malloc(size);
- } else {
- if (state->bufe - state->bufp < size) {
- return NULL;
- }
- p = state->bufp;
- state->bufp += size;
- }
- return p;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtAllocArgs --
- *
- * Grow MsgFmt_Arg array to accomodate new entry.
- *
- * Results:
- * TRUE on success.
- * State updated.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-MsgFmtAllocArgs(MsgFmtParseState *state, // IN/OUT: state structure
- int n) // IN: 1-based argument number
-{
- if (n <= state->maxArgs) {
- return TRUE;
- }
-
- /*
- * If using malloc, then reallocate() the array with some slack.
- * If using our own buffer, just grow it exactly.
- */
-
- if (state->buf == NULL) {
- void *p;
- n = MAX(4, n + state->maxArgs);
- p = realloc(state->args, n * sizeof *state->args);
- if (p == NULL) {
- return FALSE;
- }
- state->args = p;
- } else {
- if (state->args == NULL) {
- // first time
- state->args = (void *) state->bufp;
- } else {
- // growing: there must be nothing after the args array
- ASSERT((void *) state->bufp == state->args + state->maxArgs);
- }
- if ((char *) (state->args + n) > state->bufe) {
- return FALSE;
- }
- state->bufp = (char *) (state->args + n);
- }
- memset(state->args + state->maxArgs, 0,
- sizeof *state->args * (n - state->maxArgs));
- state->maxArgs = n;
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtVasprintf --
- *
- * Format a string in allocated space.
- *
- * Results:
- * String.
- *
- * Side effects:
- * Memory allocated or state updated.
- * Panic if can't allocate.
- *
- *-----------------------------------------------------------------------------
- */
-
-static char *
-MsgFmtVasprintf(MsgFmtParseState *state, // IN/OUT: state structure
- const char *fmt, // IN: error format
- va_list args) // IN: error args
-{
- char *p;
-
- ASSERT(state->error == NULL);
- if (state->buf == NULL) {
- p = Str_Vasprintf(NULL, fmt, args);
- VERIFY(p != NULL);
- } else {
- int n;
- p = state->bufp;
- // Str_Vsnprintf() may truncate
- n = Str_Vsnprintf(p, (char *)state->bufe - p, fmt, args);
- state->bufp = (n < 0) ? state->bufe : state->bufp + n + 1;
- }
- return p;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtFreeAll --
- *
- * Free all memory associated with current MsgFmt_Arg array.
- *
- * Results:
- * State updated.
- *
- * Side effects:
- * Memory may be freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-MsgFmtFreeAll(MsgFmtParseState *state) // IN/OUT: state structure
-{
- if (state->args == NULL)
- return;
-
- if (state->buf == NULL) {
- MsgFmt_FreeArgs(state->args, state->numArgs);
- } else {
- state->bufp = state->buf;
- }
- state->numArgs = state->maxArgs = 0;
- state->args = NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmtBufUsed --
- *
- * Return the amount of space used in the caller supplied buffer.
- *
- * Results:
- * size_t
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static size_t
-MsgFmtBufUsed(MsgFmtParseState *state) // IN: state structure
-{
- if (state->buf == NULL) {
- return 0;
- } else {
- return state->bufp - (char *)state->buf;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_SwizzleArgs --
- *
- * Pointer swizzling. Flattens pointers in the MsgFmt_Arg array by
- * converting them to offsets relative to the start of the args array.
- * This should only be invoked if the MsgFmt_Arg array was allocated
- * from a caller-supplied buffer from MsgFmt_GetArgsWithBuf.
- *
- * Results:
- * None.
- *
- * Side effects:
- * For all i such that args[i] is a string parameter,
- * args[i].v.offset is set to the offset from args to the start
- * of the string, or to 0 if the string was NULL.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MsgFmt_SwizzleArgs(MsgFmt_Arg *args,
- int numArgs)
-{
- int i;
- int8* bufStart = (int8*)args;
-
- for (i = 0; i < numArgs; i++) {
-
- switch (args[i].type) {
- case MSGFMT_ARG_STRING8:
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32:
- if (args[i].v.ptr == NULL) {
- // offset is never 0 otherwise
- args[i].v.offset = 0;
- } else {
- args[i].v.offset = (int8*)args[i].v.ptr - bufStart;
- }
- break;
- default:
- break;
- }
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_GetSwizzledString --
- *
- * Helper for pointer un-swizzling. Obtains the pointer encoded
- * by a swizzled argument, if it is a string and the pointer is
- * within the proper bounds.
- *
- * Results:
- * NULL and a non-zero return value if the given argument is not
- * a string, or the pointer is out of bounds (below the end of
- * the args array or above the end of the buffer), or the string
- * is not null-terminated within the buffer.
- *
- * Exception to the above: an offset of 0 is used to encode the
- * NULL pointer. In this case, yields NULL and returns zero.
- *
- * Otherwise, yields a pointer to the string and returns zero.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_GetSwizzledString(const MsgFmt_Arg *args, // IN: argument array
- int numArgs, // IN: size of the array
- int i, // IN: index into the array
- const void *bufEnd, // IN: string space bound
- const int8 **str) // OUT: the string
-{
- const int8 *bufStart = (const int8*)args;
- const int8 *strStart = (const int8*)(args + numArgs);
- const int8 *strEnd = bufEnd;
-
- switch(args[i].type) {
- case MSGFMT_ARG_STRING8:
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32:
- if (args[i].v.offset == 0) {
- // offset is never 0 otherwise
- *str = NULL;
- return 0;
- } else {
- const int8 *ptr = args[i].v.offset + bufStart;
-
- if (ptr < strStart || ptr >= strEnd
- || memchr(ptr, '\0', strEnd - ptr) == NULL) {
- *str = NULL;
- return -1;
- } else {
- *str = ptr;
- return 0;
- }
- }
- break;
- default:
- *str = NULL;
- return -1;
- }
- NOT_REACHED();
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_UnswizzleArgs --
- *
- * Pointer un-swizzling. Re-instates the pointers in the arg array.
- * This should only be invoked if the MsgFmt_Arg array was previously
- * swizzled using MsgFmt_SwizzleArgs.
- *
- * If a reconstituted pointer would be out of range -- i.e.,
- * before the end of the args array or after the provided
- * end-of-buffer pointer -- it is replaced with NULL and an error
- * is returned. This is also done if the resulting string is not
- * null-terminated within the provided bound.
- *
- * Results:
- * 0 on success; -1 in case of bad pointer.
- *
- * Side effects:
- * For all i such that args[i] is a string parameter, sets
- * args[i].v.ptr to the string previously encoded as an offset,
- * or to NULL if the offset was 0, or to NULL in case of error.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_UnswizzleArgs(MsgFmt_Arg *args, // IN/OUT: the arguments (+ strings)
- int numArgs, // IN: number of arguments
- void *bufEnd) // IN: string space bound
-{
- int i;
- int failures = 0;
-
- for (i = 0; i < numArgs; i++) {
- switch (args[i].type) {
- case MSGFMT_ARG_STRING8:
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32:
- if (MsgFmt_GetSwizzledString(args, numArgs, i, bufEnd,
- (const int8**)&args[i].v.ptr) != 0) {
- ++failures;
- }
- break;
- default:
- break;
- }
- }
- return failures > 0 ? -1 : 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_CopyArgs --
- *
- * Copy all args from the given 'copyArgs' array.
- *
- * Results:
- * Pointer to copied args array.
- *
- * Side effects:
- * Allocates memory for new args array.
- *
- *-----------------------------------------------------------------------------
- */
-
-MsgFmt_Arg*
-MsgFmt_CopyArgs(MsgFmt_Arg* copyArgs, // IN: Args to be copied
- int numArgs) // IN: number of args
-{
- MsgFmt_Arg *args;
- int i;
-
- args = malloc(numArgs * sizeof(MsgFmt_Arg));
- if (args == NULL) {
- return NULL;
- }
-
- memcpy(args, copyArgs, numArgs * sizeof(MsgFmt_Arg));
-
- for (i = 0; i < numArgs; i++) {
- switch (args[i].type) {
- case MSGFMT_ARG_STRING8:
- case MSGFMT_ARG_ERRNO:
- if (args[i].v.string8 != NULL) {
- args[i].v.string8char = strdup(copyArgs[i].v.string8char);
- if (args[i].v.string8 == NULL) {
- MsgFmt_FreeArgs(args, i);
- return NULL;
- }
- }
- break;
- case MSGFMT_ARG_STRING16:
- case MSGFMT_ARG_STRING32:
- /*
- * We don't care about these types.
- */
- NOT_IMPLEMENTED();
- break;
- default:
- break;
- }
- }
-
- return args;
-}
-
-
-#ifdef HAS_BSD_PRINTF // {
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_Snprintf --
- *
- * MsgFmt_Arg version of Str_Vsnprintf().
- *
- * Results:
- * Number of character written, not including null termination,
- * or number of characters would have been written on overflow.
- * (This is exactly the same as vsnprintf(), but different
- * from Str_Vsnprintf().)
- * String is always null terminated, even on overflow.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-MsgFmt_Snprintf(char *buf, // OUT: formatted string
- size_t size, // IN: size of buffer
- const char *format, // IN: format
- const MsgFmt_Arg *args, // IN: message arguments
- int numArgs) // IN: number of arguments
-{
- return MsgFmtSnprintfWork(&buf, size, format, args, numArgs);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MsgFmt_Asprintf --
- *
- * MsgFmt_Arg version of Str_Vasprintf().
- *
- * Results:
- * Allocated string on success.
- * NULL on failure.
- * Length of returned string (not including null termination)
- * in *length (if length != NULL).
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-char *
-MsgFmt_Asprintf(size_t *length, // OUT: length of returned string
- const char *format, // IN: format
- const MsgFmt_Arg *args, // IN: message arguments
- int numArgs) // IN: number of arguments
-{
- char *p = NULL;
- int n = MsgFmtSnprintfWork(&p, 0, format, args, numArgs);
-
- if (n < 0) {
- return NULL;
- }
- if (length != NULL) {
- *length = n;
- }
- return p;
-}
-
-static int
-MsgFmtSnprintfWork(char **outbuf, size_t bufSize, const char *fmt0,
- const MsgFmt_Arg *args, int numArgs)
-{
- char *fmt; /* format string */
- int ch; /* character from fmt */
- int n; /* handy integer (short term usage) */
- char *cp; /* handy char pointer (short term usage) */
- BSDFmt_IOV *iovp; /* for PRINT macro */
- int flags; /* flags as above */
- int ret; /* return value accumulator */
- int width; /* width from format (%8d), or 0 */
- int prec; /* precision from format; <0 for N/A */
- char sign; /* sign prefix (' ', '+', '-', or \0) */
- char thousands_sep; /* locale specific thousands separator */
- const char *grouping; /* locale specific numeric grouping rules */
-
-#ifndef NO_FLOATING_POINT
- /*
- * We can decompose the printed representation of floating
- * point numbers into several parts, some of which may be empty:
- *
- * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
- * A B ---C--- D E F
- *
- * A: 'sign' holds this value if present; '\0' otherwise
- * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
- * C: cp points to the string MMMNNN. Leading and trailing
- * zeros are not in the string and must be added.
- * D: expchar holds this character; '\0' if no exponent, e.g. %f
- * F: at least two digits for decimal, at least one digit for hex
- */
- char *decimal_point; /* locale specific decimal point */
-#if defined __ANDROID__
- static char dp = '.';
-#endif
- int signflag; /* true if float is negative */
- union { /* floating point arguments %[aAeEfFgG] */
- double dbl;
- long double ldbl;
- } fparg;
- int expt; /* integer value of exponent */
- char expchar; /* exponent character: [eEpP\0] */
- char *dtoaend; /* pointer to end of converted digits */
- int expsize; /* character count for expstr */
- int lead; /* sig figs before decimal or group sep */
- int ndig; /* actual number of digits returned by dtoa */
- char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
- char *dtoaresult; /* buffer allocated by dtoa */
- int nseps; /* number of group separators with ' */
- int nrepeats; /* number of repeats of the last group */
-#endif
- uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
- int base; /* base for [diouxX] conversion */
- int dprec; /* a copy of prec if [diouxX], 0 otherwise */
- int realsz; /* field size expanded by dprec, sign, etc */
- int size; /* size of converted field or string */
- int prsize; /* max size of printed field */
- const char *xdigs; /* digits for %[xX] conversion */
- BSDFmt_UIO uio; /* output information: summary */
- BSDFmt_IOV iov[BSDFMT_NIOV]; /* ... and individual io vectors */
- char buf[INT_CONV_BUF];/* buffer with space for digits of uintmax_t */
- char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
- int nextarg; /* 1-based argument index */
- const MsgFmt_Arg *a;
- char *convbuf; /* wide to multibyte conversion result */
- BSDFmt_StrBuf sbuf;
-
- /*
- * BEWARE, these `goto error' on error, and PAD uses `n'.
- */
-#define PRINT(ptr, len) { \
- iovp->iov_base = (ptr); \
- iovp->iov_len = (len); \
- uio.uio_resid += (len); \
- iovp++; \
- if (++uio.uio_iovcnt >= BSDFMT_NIOV) { \
- if (BSDFmt_SPrint(&sbuf, &uio)) \
- goto error; \
- iovp = iov; \
- } \
- }
-#define PAD(howmany, with) { \
- if ((n = (howmany)) > 0) { \
- while (n > PADSIZE) { \
- PRINT(with, PADSIZE); \
- n -= PADSIZE; \
- } \
- PRINT(with, n); \
- } \
- }
-#define PRINTANDPAD(p, ep, len, with) do { \
- int n2 = (ep) - (p); \
- if (n2 > (len)) \
- n2 = (len); \
- if (n2 > 0) \
- PRINT((p), n2); \
- PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
- } while(0)
-#define FLUSH() { \
- if (uio.uio_resid && BSDFmt_SPrint(&sbuf, &uio)) \
- goto error; \
- uio.uio_iovcnt = 0; \
- iovp = iov; \
- }
-
-#define FETCHARG(a, i) do { \
- int ii = (i) - 1; \
- if (ii >= numArgs) { \
- sbuf.error = TRUE; \
- goto error; \
- } \
- (a) = args + ii; \
-} while (FALSE)
-
- /*
- * Get * arguments, including the form *nn$.
- */
-#define GETASTER(val) do { \
- int n2 = 0; \
- char *cp = fmt; \
- const MsgFmt_Arg *a; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- FETCHARG(a, n2); \
- fmt = cp + 1; \
- } else { \
- FETCHARG(a, nextarg++); \
- } \
- if (a->type != MSGFMT_ARG_INT32) { \
- sbuf.error = TRUE; \
- goto error; \
- } \
- val = a->v.signed32; \
-} while (FALSE)
-
- xdigs = xdigs_lower;
- thousands_sep = '\0';
- grouping = NULL;
- convbuf = NULL;
-#ifndef NO_FLOATING_POINT
- dtoaresult = NULL;
-#if defined __ANDROID__
- /*
- * Struct lconv is not working! For decimal_point,
- * using '.' instead is a workaround.
- */
- NOT_TESTED();
- decimal_point = &dp;
-#else
- decimal_point = localeconv()->decimal_point;
-#endif
-#endif
-
- fmt = (char *)fmt0;
- nextarg = 1;
- uio.uio_iov = iovp = iov;
- uio.uio_resid = 0;
- uio.uio_iovcnt = 0;
- ret = 0;
-
- /*
- * Set up output string buffer structure.
- */
-
- sbuf.alloc = *outbuf == NULL;
- sbuf.error = FALSE;
- sbuf.buf = *outbuf;
- sbuf.size = bufSize;
- sbuf.index = 0;
-
- /*
- * If asprintf(), allocate initial buffer based on format length.
- * Empty format only needs one byte.
- * Otherwise, round up to multiple of 64.
- */
-
- if (sbuf.alloc) {
- size_t n = strlen(fmt0) + 1; // +1 for \0
- if (n > 1) {
- n = ROUNDUP(n, 64);
- }
- if ((sbuf.buf = malloc(n * sizeof (char))) == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- sbuf.size = n;
- }
-
- // shut compile up
-#ifndef NO_FLOATING_POINT
- expt = 0;
- expchar = 0;
- dtoaend = NULL;
- expsize = 0;
- lead = 0;
- ndig = 0;
- nseps = 0;
- nrepeats = 0;
-#endif
- ujval = 0;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if ((n = fmt - cp) != 0) {
- if ((unsigned)ret + n > INT_MAX) {
- ret = EOF;
- goto error;
- }
- PRINT(cp, n);
- ret += n;
- }
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
- dprec = 0;
- width = 0;
- prec = -1;
- sign = '\0';
- ox[1] = '\0';
-
- rflag: ch = *fmt++;
- reswitch: switch (ch) {
- case ' ':
- /*-
- * ``If the space and + flags both appear, the space
- * flag will be ignored.''
- * -- ANSI X3J11
- */
- if (!sign)
- sign = ' ';
- goto rflag;
- case '#':
- flags |= ALT;
- goto rflag;
- case '*':
- /*-
- * ``A negative field width argument is taken as a
- * - flag followed by a positive field width.''
- * -- ANSI X3J11
- * They don't exclude field widths read from args.
- */
- GETASTER (width);
- if (width >= 0)
- goto rflag;
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '\'':
- flags |= GROUPING;
-#if defined __ANDROID__
- /*
- * Struct lconv is not working! The code below is a workaround.
- */
- NOT_TESTED();
- thousands_sep = ',';
-#else
- thousands_sep = *(localeconv()->thousands_sep);
- grouping = localeconv()->grouping;
-#endif
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- GETASTER (prec);
- goto rflag;
- }
- prec = 0;
- while (is_digit(ch)) {
- prec = 10 * prec + to_digit(ch);
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- /*-
- * ``Note that 0 is taken as a flag, not as the
- * beginning of a field width.''
- * -- ANSI X3J11
- */
- flags |= ZEROPAD;
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- if (ch == '$') {
- nextarg = n;
- goto rflag;
- }
- width = n;
- goto reswitch;
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'I':
- /* could be I64 - long long int is 64bit */
- if (fmt[0] == '6' && fmt[1] == '4') {
- fmt += 2;
- flags |= LLONGINT;
- goto rflag;
- }
- /* could be I32 - normal int is 32bit */
- if (fmt[0] == '3' && fmt[1] == '2') {
- fmt += 2;
- /* flags |= normal integer - it is 32bit for all our targets */
- goto rflag;
- }
- /*
- * I alone - use Microsoft's semantic as size_t modifier. We do
- * not support glibc's semantic to use alternative digits.
- */
- flags |= SIZET;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'L':
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'Z':
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
- FETCHARG(a, nextarg++);
- if (a->type != MSGFMT_ARG_INT32) {
- sbuf.error = TRUE;
- goto error;
- }
- if (flags & LONGINT) {
- static const mbstate_t initial;
- mbstate_t mbs;
- size_t mbseqlen;
-
- mbs = initial;
- // XXX must deal with mismatch between wchar_t size
- mbseqlen = wcrtomb(cp = buf, (wchar_t)a->v.signed32, &mbs);
- if (mbseqlen == (size_t)-1) {
- sbuf.error = TRUE;
- goto error;
- }
- size = (int)mbseqlen;
- } else {
- *(cp = buf) = a->v.signed32;
- size = 1;
- }
- sign = '\0';
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- FETCHARG(a, nextarg++);
- if ((flags & (INTMAXT|LLONGINT)) != 0) {
- if (a->type == MSGFMT_ARG_INT64) {
- ujval = a->v.signed64;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & (SIZET|PTRDIFFT|LONGINT)) != 0) {
- if (a->type == MSGFMT_ARG_INT64) {
- ujval = a->v.signed64;
- } else if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) a->v.signed32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & SHORTINT) != 0) {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) (short) a->v.signed32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & CHARINT) != 0) {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) (signed char) a->v.signed32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) a->v.signed32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- }
- if ((intmax_t)ujval < 0) {
- ujval = -ujval;
- sign = '-';
- }
- base = 10;
- goto number;
-#ifndef NO_FLOATING_POINT
- case 'e':
- case 'E':
- expchar = ch;
- if (prec < 0) /* account for digit before decpt */
- prec = DEFPREC + 1;
- else
- prec++;
- goto fp_begin;
- case 'f':
- case 'F':
- expchar = '\0';
- goto fp_begin;
- case 'g':
- case 'G':
- expchar = ch - ('g' - 'e');
- if (prec == 0)
- prec = 1;
- fp_begin:
- if (flags & LLONGINT) {
- sbuf.error = TRUE;
- goto error;
- }
- if (prec < 0)
- prec = DEFPREC;
- if (dtoaresult != NULL)
- freedtoa(dtoaresult);
- FETCHARG(a, nextarg++);
- if (a->type != MSGFMT_ARG_FLOAT64) {
- sbuf.error = TRUE;
- goto error;
- }
- fparg.dbl = a->v.float64;
-#if defined NO_DTOA
- NOT_TESTED();
- dtoaresult = NULL;
- sbuf.error = TRUE;
-
- goto error;
-#else
- dtoaresult = cp =
- dtoa(fparg.dbl, expchar ? 2 : 3, prec,
- &expt, &signflag, &dtoaend);
-#endif
- if (expt == 9999)
- expt = INT_MAX;
- if (signflag)
- sign = '-';
- if (expt == INT_MAX) { /* inf or nan */
- if (*cp == 'N') {
- cp = (ch >= 'a') ? "nan" : "NAN";
- sign = '\0';
- } else
- cp = (ch >= 'a') ? "inf" : "INF";
- size = 3;
- break;
- }
- flags |= FPT;
- ndig = dtoaend - cp;
- if (ch == 'g' || ch == 'G') {
- if (expt > -4 && expt <= prec) {
- /* Make %[gG] smell like %[fF] */
- expchar = '\0';
- if (flags & ALT)
- prec -= expt;
- else
- prec = ndig - expt;
- if (prec < 0)
- prec = 0;
- } else {
- /*
- * Make %[gG] smell like %[eE], but
- * trim trailing zeroes if no # flag.
- */
- if (!(flags & ALT))
- prec = ndig;
- }
- }
- if (expchar) {
- expsize = BSDFmt_Exponent(expstr, expt - 1, expchar);
- size = expsize + prec;
- if (prec > 1 || flags & ALT)
- ++size;
- } else {
- /* space for digits before decimal point */
- if (expt > 0)
- size = expt;
- else /* "0" */
- size = 1;
- /* space for decimal pt and following digits */
- if (prec || flags & ALT)
- size += prec + 1;
- if (grouping && expt > 0) {
- /* space for thousands' grouping */
- nseps = nrepeats = 0;
- lead = expt;
- while (*grouping != CHAR_MAX) {
- if (lead <= *grouping)
- break;
- lead -= *grouping;
- if (*(grouping+1)) {
- nseps++;
- grouping++;
- } else
- nrepeats++;
- }
- size += nseps + nrepeats;
- } else
- lead = expt;
- }
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- sbuf.error = TRUE;
- goto error;
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- base = 8;
- goto get_unsigned;
- case 'p':
- /*-
- * ``The argument shall be a pointer to void. The
- * value of the pointer is converted to a sequence
- * of printable characters, in an implementation-
- * defined manner.''
- * -- ANSI X3J11
- */
- FETCHARG(a, nextarg++);
- if (a->type == MSGFMT_ARG_PTR32) {
- ujval = a->v.unsigned32;
- } else if (a->type == MSGFMT_ARG_PTR64) {
- ujval = a->v.unsigned64;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- base = 16;
- xdigs = xdigs_upper;
- flags = flags | INTMAXT;
- /*
- * PR 103201
- * VisualC sscanf doesn't grok '0x', so prefix zeroes.
- */
-// ox[1] = 'x';
- goto nosign;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- FETCHARG(a, nextarg++);
- if (flags & LONGINT) {
- wchar_t *wcp;
-#if defined __ANDROID__
- ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
- sizeof (wchar_t) == sizeof (int32) ||
- sizeof (wchar_t) == sizeof (int8));
- if ((sizeof (wchar_t) == sizeof (int16) &&
- a->type != MSGFMT_ARG_STRING16) ||
- (sizeof (wchar_t) == sizeof (int32) &&
- a->type != MSGFMT_ARG_STRING32) ||
- (sizeof (wchar_t) == sizeof (int8) &&
- a->type != MSGFMT_ARG_STRING8)) {
-#else
- ASSERT_ON_COMPILE(sizeof (wchar_t) == 2 || sizeof (wchar_t) == 4);
- if (sizeof (wchar_t) == 2 ?
- a->type != MSGFMT_ARG_STRING16 :
- a->type != MSGFMT_ARG_STRING32) {
-#endif
- sbuf.error = TRUE;
- goto error;
- }
- if ((wcp = (wchar_t *) a->v.ptr) == NULL)
- cp = "(null)";
- else {
- if (convbuf != NULL)
- free(convbuf);
- convbuf = BSDFmt_WCharToUTF8(wcp, prec);
- if (convbuf == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- cp = convbuf;
- }
- } else {
- if (a->type != MSGFMT_ARG_STRING8 &&
- a->type != MSGFMT_ARG_ERRNO) {
- sbuf.error = TRUE;
- goto error;
- }
-
- /*
- * Use localized string (in localString) if available.
- * Strip off Msg ID if unlocalized string has one.
- * Use (null) for null pointer.
- */
-
- if (a->p.localString != NULL) {
- cp = a->p.localString;
- } else if (a->v.string8 != NULL) {
- cp = (char *) Msg_StripMSGID(a->v.string8char);
- } else {
- cp = "(null)";
- }
- }
- if (prec >= 0) {
- /*
- * We can use strlen here because the string is always
- * terminated, unlike the string passed to MsgFmt_GetArgs.
- * However, it's somewhat faster to use memchr.
- */
- char *p = memchr(cp, 0, prec);
-
- if (p != NULL) {
- size = p - cp;
- if (size > prec)
- size = prec;
- } else
- size = prec;
- } else
- size = strlen(cp);
- sign = '\0';
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- base = 10;
- goto get_unsigned;
- case 'X':
- xdigs = xdigs_upper;
- goto hex;
- case 'x':
- xdigs = xdigs_lower;
- hex:
- base = 16;
- if (flags & ALT)
- ox[1] = ch;
- flags &= ~GROUPING;
-
- get_unsigned:
- FETCHARG(a, nextarg++);
- if ((flags & (INTMAXT|LLONGINT)) != 0) {
- if (a->type == MSGFMT_ARG_INT64) {
- ujval = a->v.unsigned64;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & (SIZET|PTRDIFFT|LONGINT)) != 0) {
- if (a->type == MSGFMT_ARG_INT64) {
- ujval = a->v.unsigned64;
- } else if (a->type == MSGFMT_ARG_INT32) {
- ujval = (uintmax_t) a->v.unsigned32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & SHORTINT) != 0) {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) (unsigned short) a->v.unsigned32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else if ((flags & CHARINT) != 0) {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) (unsigned char) a->v.unsigned32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- } else {
- if (a->type == MSGFMT_ARG_INT32) {
- ujval = (intmax_t) a->v.unsigned32;
- } else {
- sbuf.error = TRUE;
- goto error;
- }
- }
- if (ujval == 0) /* squash 0x/X if zero */
- ox[1] = '\0';
-
- /* unsigned conversions */
- nosign:
- sign = '\0';
- /*-
- * ``... diouXx conversions ... if a precision is
- * specified, the 0 flag will be ignored.''
- * -- ANSI X3J11
- */
- number:
- if ((dprec = prec) >= 0)
- flags &= ~ZEROPAD;
-
- /*-
- * ``The result of converting a zero value with an
- * explicit precision of zero is no characters.''
- * -- ANSI X3J11
- *
- * ``The C Standard is clear enough as is. The call
- * printf("%#.0o", 0) should print 0.''
- * -- Defect Report #151
- */
- cp = buf + INT_CONV_BUF;
- if (ujval != 0 || prec != 0 ||
- (flags & ALT && base == 8))
- cp = BSDFmt_UJToA(ujval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- size = buf + INT_CONV_BUF - cp;
- if (size > INT_CONV_BUF) /* should never happen */
- abort();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- /* pretend it was %c with argument ch */
- cp = buf;
- *cp = ch;
- size = 1;
- sign = '\0';
- break;
- }
-
- /*
- * All reasonable formats wind up here. At this point, `cp'
- * points to a string which (if not flags&LADJUST) should be
- * padded out to `width' places. If flags&ZEROPAD, it should
- * first be prefixed by any sign or other prefix; otherwise,
- * it should be blank padded before the prefix is emitted.
- * After any left-hand padding and prefixing, emit zeroes
- * required by a decimal [diouxX] precision, then print the
- * string proper, then emit zeroes required by any leftover
- * floating precision; finally, if LADJUST, pad with blanks.
- *
- * Compute actual size, so we know how much to pad.
- * size excludes decimal prec; realsz includes it.
- */
- realsz = dprec > size ? dprec : size;
- if (sign)
- realsz++;
- if (ox[1])
- realsz += 2;
-
- prsize = width > realsz ? width : realsz;
- if ((unsigned)ret + prsize > INT_MAX) {
- ret = EOF;
- goto error;
- }
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST|ZEROPAD)) == 0)
- PAD(width - realsz, blanks);
-
- /* prefix */
- if (sign)
- PRINT(&sign, 1);
-
- if (ox[1]) { /* ox[1] is either x, X, or \0 */
- ox[0] = '0';
- PRINT(ox, 2);
- }
-
- /* right-adjusting zero padding */
- if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
- PAD(width - realsz, zeroes);
-
- /* leading zeroes from decimal precision */
- PAD(dprec - size, zeroes);
-
- /* the string or number proper */
-#ifndef NO_FLOATING_POINT
- if ((flags & FPT) == 0) {
- PRINT(cp, size);
- } else { /* glue together f_p fragments */
- if (!expchar) { /* %[fF] or sufficiently short %[gG] */
- if (expt <= 0) {
- PRINT(zeroes, 1);
- if (prec || flags & ALT)
- PRINT(decimal_point, 1);
- PAD(-expt, zeroes);
- /* already handled initial 0's */
- prec += expt;
- } else {
- PRINTANDPAD(cp, dtoaend, lead, zeroes);
- cp += lead;
- if (grouping) {
- while (nseps>0 || nrepeats>0) {
- if (nrepeats > 0)
- nrepeats--;
- else {
- grouping--;
- nseps--;
- }
- PRINT(&thousands_sep,
- 1);
- PRINTANDPAD(cp,dtoaend,
- *grouping, zeroes);
- cp += *grouping;
- }
- if (cp > dtoaend)
- cp = dtoaend;
- }
- if (prec || flags & ALT)
- PRINT(decimal_point,1);
- }
- PRINTANDPAD(cp, dtoaend, prec, zeroes);
- } else { /* %[eE] or sufficiently long %[gG] */
- if (prec > 1 || flags & ALT) {
- buf[0] = *cp++;
- buf[1] = *decimal_point;
- PRINT(buf, 2);
- PRINT(cp, ndig-1);
- PAD(prec - ndig, zeroes);
- } else /* XeYYY */
- PRINT(cp, 1);
- PRINT(expstr, expsize);
- }
- }
-#else
- PRINT(cp, size);
-#endif
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST)
- PAD(width - realsz, blanks);
-
- /* finally, adjust ret */
- ret += prsize;
-
- FLUSH(); /* copy out the I/O vectors */
- }
-done:
- FLUSH();
-
- /*
- * Always null terminate, unless buffer is size 0.
- */
-
- ASSERT(!sbuf.error && ret >= 0);
- if (sbuf.size <= 0) {
- ASSERT(!sbuf.alloc);
- } else {
- ASSERT(sbuf.index < sbuf.size);
- sbuf.buf[sbuf.index] = '\0';
- }
-
-error:
-#ifndef NO_FLOATING_POINT
- if (dtoaresult != NULL)
- freedtoa(dtoaresult);
-#endif
- if (convbuf != NULL)
- free(convbuf);
- if (sbuf.error) {
- ret = EOF;
- }
-
- // return allocated buffer on success, free it on failure
- if (sbuf.alloc) {
- if (ret < 0) {
- free(sbuf.buf);
- } else {
- *outbuf = sbuf.buf;
- }
- }
-
- return (ret);
- /* NOTREACHED */
-
-#undef PRINT
-#undef PAD
-#undef PRINTANDPAD
-#undef FLUSH
-#undef FETCHARG
-#undef GETASTER
-}
-
-#endif // }
libString_la_SOURCES =
-if USE_PRINTF_WRAPPERS
- libString_la_SOURCES += bsd_output_shared.c
- libString_la_SOURCES += bsd_vsnprintf.c
- libString_la_SOURCES += bsd_vsnwprintf.c
-endif
-
-libString_la_SOURCES += convertutf.c
libString_la_SOURCES += str.c
-
+++ /dev/null
-/* **********************************************************
- * Copyright 2006 VMware, Inc. All rights reserved.
- * **********************************************************/
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * bsd_output_int.h --
- *
- * Declarations private to the BSD-borrowed formatted output
- * funtions.
- */
-
-#ifndef _BSD_OUTPUT_INT_H_
-#define _BSD_OUTPUT_INT_H_
-
-#define INCLUDE_ALLOW_USERLEVEL
-#include "includeCheck.h"
-
-#include "bsd_output.h"
-#include "bsdfmt.h"
-
-union arg {
- int intarg;
- u_int uintarg;
- long longarg;
- u_long ulongarg;
- long long longlongarg;
- unsigned long long ulonglongarg;
- ptrdiff_t ptrdiffarg;
- size_t sizearg;
- intmax_t intmaxarg;
- uintmax_t uintmaxarg;
- void *pvoidarg;
- char *pchararg;
- signed char *pschararg;
- short *pshortarg;
- int *pintarg;
- long *plongarg;
- long long *plonglongarg;
- ptrdiff_t *pptrdiffarg;
- size_t *psizearg;
- intmax_t *pintmaxarg;
-#ifndef NO_FLOATING_POINT
- double doublearg;
- long double longdoublearg;
-#endif
- wint_t wintarg;
- wchar_t *pwchararg;
-};
-
-/*
- * Type ids for argument type table.
- */
-enum typeid {
- T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
- T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
- T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
- T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
- T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
-};
-
-extern wint_t
-bsd_btowc(int c);
-
-#endif // _BSD_OUTPUT_INT_H_
+++ /dev/null
-/* **********************************************************
- * Copyright 2006 VMware, Inc. All rights reserved.
- * **********************************************************/
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * Shared code common to the bsd_output_* implementation files.
- */
-
-//#include <sys/cdefs.h>
-
-#if !defined(STR_NO_WIN32_LIBS) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef _WIN32
-#include <stddef.h>
-#include <stdint.h>
-#endif
-#include <stdarg.h>
-#include <math.h>
-#include <string.h>
-#include <wchar.h>
-#ifdef __APPLE__
-#include <pthread.h>
-#endif
-#if !defined(_WIN32) || !defined(__APPLE__)
-/* required to handle %.20f conversion of 1e308 */
-#define FP_BUFFERSIZE 349
-#endif
-
-#include "vmware.h"
-#include "bsd_output_int.h"
-
-#ifndef NO_FLOATING_POINT
-
-/*
- *-----------------------------------------------------------------------------
- *
- * dtoa --
- *
- * Pretend to be like the mysterious dtoa function in the FreeBSD
- * libc source code. It appears to take a double argument, and then
- * return an ASCII character string representation of this number -
- * just digits, no sign, decimal point, or exponent symbol.
- *
- * If 'mode' is 3, then 'prec' limits the number of digits after the
- * decimal point, if 'mode' is 2, then total digits.
- *
- * The base-10 exponent of the number is returned in 'expOut'.
- *
- * 'sign' is returned as 0 for a positive number, otherwise negative.
- *
- * 'strEnd' is returned as a pointer to the end of the number in the
- * string, so don't rely on NULL-termination to tell you where the
- * number ends.
- *
- * Results:
- *
- * The allocated string on success (free with freedtoa), NULL on
- * failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-char *
-dtoa(double d, // IN
- int mode, // IN
- int prec, // IN
- int *expOut, // OUT
- int *sign, // OUT
- char **strEnd) // OUT
-{
- char *str;
- int dec;
-
-#if defined(_WIN32)
- if (2 == mode) {
- str = malloc(_CVTBUFSIZE);
- if (str) {
- if (_ecvt_s(str, _CVTBUFSIZE, d, prec, &dec, sign)) {
- free(str);
- str = NULL;
- }
- }
- } else {
- ASSERT(3 == mode);
- str = malloc(_CVTBUFSIZE);
- if (str) {
- if (_fcvt_s(str, _CVTBUFSIZE, d, prec, &dec, sign)) {
- free(str);
- str = NULL;
- }
- }
-
- /*
- * When the value is not zero but rounds to zero at prec digits,
- * the Windows fcvt() sometimes returns the empty string and
- * a negative dec that goes too far (as in -dec > prec).
- * For example, converting 0.001 with prec 1 results in
- * the empty string and dec -2. (See bug 253674.)
- *
- * We just clamp dec to -prec when this happens.
- *
- * While this may appear to be a safe and good thing to
- * do in general. It really only works when the result is
- * all zeros or empty. Since checking for all zeros is
- * expensive, we only check for empty string, which works
- * for this bug.
- */
-
- if (str && *str == '\0' && dec < 0 && dec < -prec) {
- dec = -prec;
- }
- }
-#elif __APPLE__
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
- if (2 == mode) {
- pthread_mutex_lock(&mutex);
- str = strdup(ecvt(d, prec, &dec, sign));
- pthread_mutex_unlock(&mutex);
- } else {
- ASSERT(3 == mode);
-
- /*
- * The Mac fcvt() returns "" when prec is 0, so we have to
- * compensate. See bug 233530.
- * While it is conceivable that fcvt(round(d), 1) can return
- * a string that doesn't end in 0, it doesn't seem to happen
- * in practice (on the Mac). The problematic case that we
- * want to avoid is a last digit greater than 4, which requires
- * rounding up, which we don't want to do, which is why we're
- * doing the rounding on the number instead of after fcvt()
- * in the first place.
- * -- edward
- */
-
- if (prec == 0) {
- size_t l;
- pthread_mutex_lock(&mutex);
- str = strdup(fcvt(round(d), 1, &dec, sign));
- pthread_mutex_unlock(&mutex);
- if (str) {
- l = strlen(str);
- ASSERT(l > 0);
- l--;
- ASSERT(str[l] == '0');
- str[l] = '\0';
- }
- } else {
- pthread_mutex_lock(&mutex);
- str = strdup(fcvt(d, prec, &dec, sign));
- pthread_mutex_unlock(&mutex);
- }
- }
-#else
- if (2 == mode) {
- char buf[FP_BUFFERSIZE];
-
- str =
- ecvt_r(d, prec, &dec, sign, buf, sizeof buf) != 0 ? NULL : strdup(buf);
- } else {
- char buf[FP_BUFFERSIZE];
-
- ASSERT(3 == mode);
- str =
- fcvt_r(d, prec, &dec, sign, buf, sizeof buf) != 0 ? NULL : strdup(buf);
- }
-#endif // _WIN32
-
- if (str) {
- *strEnd = str + strlen(str);
-
- /* strip trailing zeroes */
- while ((*strEnd > str) && ('0' == *((*strEnd) - 1))) {
- (*strEnd)--;
- }
-
- *expOut = dec;
- }
-
- return str;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ldtoa --
- *
- * A dtoa wrapper that simply casts its long double argument to a
- * double. Windows can't handle long double.
- *
- * Results:
- * See dtoa.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-char *
-ldtoa(long double *ld, int mode, int prec, int *exp, int *sign, char **strEnd)
-{
- double d = (double) *ld; // ghetto fabulous
- return dtoa(d, mode, prec, exp, sign, strEnd);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * freedtoa --
- *
- * Free the result of dtoa and ldtoa.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-freedtoa(void *mem)
-{
- free(mem);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * btowc --
- *
- * From FreeBSD. Convert the MBCS character 'c' to a wide character.
- *
- * Results:
- * The wide character on success, WEOF on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-wint_t
-bsd_btowc(int c)
-{
- char cc;
- wchar_t wc;
-
- if (c == EOF)
- return (WEOF);
- /*
- * We expect mbtowc() to return 0 or 1, hence the check for n > 1
- * which detects error return values as well as "impossible" byte
- * counts.
- */
- cc = (char)c;
- if (mbtowc(&wc, &cc, 1) > 1)
- return (WEOF);
- return (wc);
-}
-
-#endif /* !NO_FLOATING_POINT */
-
-#endif /* !STR_NO_WIN32_LIBS|*BSD */
+++ /dev/null
-/* **********************************************************
- * Copyright (C) 2006-2016 VMware, Inc. All rights reserved.
- * **********************************************************/
-
-/*
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * Note - this code originated as the file vfprintf.c in the FreeBSD
- * source code, location src/lib/libc/stdio/vfprintf.c, revision
- * 1.72. It has been borrowed and modified to act like vsnprintf
- * instead. For now, it only works for Windows. See bsd_output.h for
- * more.
- *
- * If you care to compare, the original is checked into this directory
- * as bsd_vsnprintf_orig.c.
- */
-
-#if !defined(STR_NO_WIN32_LIBS) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
-
-/*
- * Actual printf innards.
- *
- * This code is large and complicated...
- */
-
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <limits.h>
-#include <locale.h>
-#ifndef _WIN32
-#include <stddef.h>
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-
-#include "vmware.h"
-#include "bsd_output_int.h"
-#include "codeset.h"
-#include "convertutf.h"
-#include "str.h"
-
-
-#if defined __ANDROID__
-/*
- * Android doesn't support dtoa() or ldtoa().
- */
-#define NO_DTOA
-#define NO_LDTOA
-#endif
-
-static char *__ultoa(u_long, char *, int, int, const char *, int, char,
- const char *);
-static void __find_arguments(const char *, va_list, union arg **);
-static void __grow_type_table(int, enum typeid **, int *);
-
-char blanks[PADSIZE] =
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
-char zeroes[PADSIZE] =
- {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
-
-const char xdigs_lower[17] = "0123456789abcdef?";
-const char xdigs_upper[17] = "0123456789ABCDEF?";
-
-static Bool isLenientConversion = TRUE;
-
-int
-BSDFmt_SFVWrite(BSDFmt_StrBuf *sbuf, BSDFmt_UIO *uio)
-{
- int i;
- BSDFmt_IOV *siov;
-
- /*
- * If asprintf(), then grow the buffer as necessary.
- */
-
- if (sbuf->alloc) {
- size_t n = sbuf->index + uio->uio_resid + 1; // +1 for \0
-
- if (n > sbuf->size) {
- char *p;
-
- ASSERT(sbuf->size > 0);
- n = ROUNDUP(n, sbuf->size);
- if ((p = realloc(sbuf->buf, n)) == NULL) {
- sbuf->error = TRUE;
- return 1;
- }
- sbuf->buf = p;
- sbuf->size = n;
- }
- }
-
- for (i = 0, siov = uio->uio_iov; i < uio->uio_iovcnt; i++, siov++) {
- int numToWrite = sbuf->size - sbuf->index - 1; // -1 for \0
-
- /*
- * Overflowing the buffer is not an error.
- * We just silently truncate because that's what snprintf() does.
- *
- * Always leave space for null termination.
- */
-
- if (numToWrite > siov->iov_len) {
- numToWrite = siov->iov_len;
- }
-
- memcpy(sbuf->buf + sbuf->index, siov->iov_base, numToWrite);
- sbuf->index += numToWrite;
- }
-
- return 0;
-}
-
-/*
- * Flush out all the vectors defined by the given uio,
- * then reset it so that it can be reused.
- */
-int
-BSDFmt_SPrint(BSDFmt_StrBuf *sbuf, BSDFmt_UIO *uio)
-{
- int err;
-
- if (uio->uio_resid == 0) {
- uio->uio_iovcnt = 0;
- return (0);
- }
-
- err = BSDFmt_SFVWrite(sbuf, uio);
- uio->uio_resid = 0;
- uio->uio_iovcnt = 0;
-
- return err;
-}
-
-/*
- * Convert an unsigned long to ASCII for printf purposes, returning
- * a pointer to the first character of the string representation.
- * Octal numbers can be forced to have a leading zero; hex numbers
- * use the given digits.
- */
-static char *
-__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs,
- int needgrp, char thousep, const char *grp)
-{
- char *cp = endp;
- long sval;
- int ndig;
-
- /*
- * Handle the three cases separately, in the hope of getting
- * better/faster code.
- */
- switch (base) {
- case 10:
- if (val < 10) { /* many numbers are 1 digit */
- *--cp = to_char(val);
- return (cp);
- }
- ndig = 0;
- /*
- * On many machines, unsigned arithmetic is harder than
- * signed arithmetic, so we do at most one unsigned mod and
- * divide; this is sufficient to reduce the range of
- * the incoming value to where signed arithmetic works.
- */
- if (val > LONG_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = val / 10;
- } else {
- sval = val;
- }
-
- do {
- *--cp = to_char(sval % 10);
- ndig++;
-
- /*
- * If (*grp == CHAR_MAX) then no more grouping
- * should be performed.
- */
-
- if (needgrp && ndig == *grp && *grp != CHAR_MAX && sval > 9) {
- *--cp = thousep;
- ndig = 0;
-
- /*
- * If (*(grp+1) == '\0') then we have to* use *grp character
- * (last grouping rule) for all next cases
- */
-
- if (*(grp+1) != '\0') {
- grp++;
- }
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
-
- if (octzero && *cp != '0') {
- *--cp = '0';
- }
- break;
-
- case 16:
- do {
- *--cp = xdigs[val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default: /* oops */
- abort();
- }
- return (cp);
-}
-
-/* Identical to __ultoa, but for intmax_t. */
-char *
-BSDFmt_UJToA(uintmax_t val, char *endp, int base, int octzero,
- const char *xdigs, int needgrp, char thousep, const char *grp)
-{
- char *cp = endp;
- intmax_t sval;
- int ndig;
-
- /* quick test for small values; __ultoa is typically much faster */
- /* (perhaps instead we should run until small, then call __ultoa?) */
- if (val <= ULONG_MAX) {
- return (__ultoa((u_long)val, endp, base, octzero, xdigs,
- needgrp, thousep, grp));
- }
-
- switch (base) {
- case 10:
- if (val < 10) {
- *--cp = to_char(val % 10);
- return (cp);
- }
- ndig = 0;
- if (val > INTMAX_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = val / 10;
- } else {
- sval = val;
- }
- do {
- *--cp = to_char(sval % 10);
- ndig++;
- /*
- * If (*grp == CHAR_MAX) then no more grouping should be performed.
- */
-
- if (needgrp && *grp != CHAR_MAX && ndig == *grp && sval > 9) {
- *--cp = thousep;
- ndig = 0;
-
- /*
- * If (*(grp+1) == '\0') then we have to use *grp character
- * (last grouping rule) for all next cases
- */
-
- if (*(grp+1) != '\0') {
- grp++;
- }
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
-
- if (octzero && *cp != '0') {
- *--cp = '0';
- }
- break;
-
- case 16:
- do {
- *--cp = xdigs[val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default:
- abort();
- }
- return (cp);
-}
-
-/*
- * Convert a wide character string argument to a UTF-8 string
- * representation. If not -1, 'prec' specifies the maximum number of
- * bytes to output. The returned string is always NUL-terminated, even
- * if that results in the string exceeding 'prec' bytes.
- */
-char *
-BSDFmt_WCharToUTF8(wchar_t *wcsarg, int prec)
-{
- ConversionResult cres;
- char *sourceStart, *sourceEnd;
- char *targStart, *targEnd;
- char *targ = NULL;
- size_t targSize;
- size_t sourceSize = wcslen(wcsarg) * sizeof(wchar_t);
-
- targSize = (-1 == prec) ? sourceSize : MIN(sourceSize, prec);
-
- while (TRUE) {
- /*
- * Pad by 4, because we need to NUL-terminate.
- */
- targ = realloc(targ, targSize + 4);
- if (!targ) {
- goto exit;
- }
-
- targStart = targ;
- targEnd = targStart + targSize;
- sourceStart = (char *) wcsarg;
- sourceEnd = sourceStart + sourceSize;
-
- if (2 == sizeof(wchar_t)) {
- cres = ConvertUTF16toUTF8((const UTF16 **) &sourceStart,
- (const UTF16 *) sourceEnd,
- (UTF8 **) &targStart,
- (UTF8 *) targEnd,
- isLenientConversion);
- } else if (4 == sizeof(wchar_t)) {
- cres = ConvertUTF32toUTF8((const UTF32 **) &sourceStart,
- (const UTF32 *) sourceEnd,
- (UTF8 **) &targStart,
- (UTF8 *) targEnd,
- isLenientConversion);
- } else {
- NOT_IMPLEMENTED();
- }
-
- if (targetExhausted == cres) {
- if (targSize == prec) {
- /*
- * We've got all the caller wants.
- */
- break;
- } else {
- /*
- * Double buffer.
- */
- targSize = (-1 == prec) ? targSize * 2 : MIN(targSize * 2, prec);
- }
- } else if ((sourceExhausted == cres) ||
- (sourceIllegal == cres)) {
- /*
- * If lenient, the API converted all it could, so just
- * proceed, otherwise, barf.
- */
- if (isLenientConversion) {
- break;
- } else {
- free(targ);
- targ = NULL;
- goto exit;
- }
- } else if (conversionOK == cres) {
- break;
- } else {
- NOT_IMPLEMENTED();
- }
- }
-
- /*
- * Success, NUL-terminate. (The API updated targStart for us).
- */
- ASSERT(targStart <= targEnd);
- targSize = targStart - targ;
- memset(targ + targSize, 0, 4);
-
- exit:
- return targ;
-}
-
-
-int
-bsd_vsnprintf_core(char **outbuf,
- char *groupingIn,
- char thousands_sepIn,
- char *decimal_point,
- size_t bufSize,
- const char *fmt0,
- va_list ap)
-{
- char *fmt; /* format string */
- int ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- char *cp; /* handy char pointer (short term usage) */
- BSDFmt_IOV *iovp; /* for PRINT macro */
- int flags; /* flags as above */
- int ret; /* return value accumulator */
- int width; /* width from format (%8d), or 0 */
- int prec; /* precision from format; <0 for N/A */
- char sign; /* sign prefix (' ', '+', '-', or \0) */
- char thousands_sep; /* locale specific thousands separator */
- char *grouping; /* locale specific numeric grouping rules */
-
-#if !defined(NO_FLOATING_POINT)
- /*
- * We can decompose the printed representation of floating
- * point numbers into several parts, some of which may be empty:
- *
- * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
- * A B ---C--- D E F
- *
- * A: 'sign' holds this value if present; '\0' otherwise
- * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
- * C: cp points to the string MMMNNN. Leading and trailing
- * zeros are not in the string and must be added.
- * D: expchar holds this character; '\0' if no exponent, e.g. %f
- * F: at least two digits for decimal, at least one digit for hex
- */
-#if defined __ANDROID__
- static char dp = '.';
-#endif
- int signflag; /* true if float is negative */
- union { /* floating point arguments %[aAeEfFgG] */
- double dbl;
- long double ldbl;
- } fparg;
- int expt = 0; /* integer value of exponent */
- char expchar; /* exponent character: [eEpP\0] */
- char *dtoaend; /* pointer to end of converted digits */
- int expsize; /* character count for expstr */
- int lead; /* sig figs before decimal or group sep */
- int ndig; /* actual number of digits returned by dtoa */
- char expstr[MAXEXPDIG + 2]; /* buffer for exponent string: e+ZZZ */
- char *dtoaresult; /* buffer allocated by dtoa */
- int nseps; /* number of group separators with ' */
- int nrepeats; /* number of repeats of the last group */
-#endif
- u_long ulval; /* integer arguments %[diouxX] */
- uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
- int base; /* base for [diouxX] conversion */
- int dprec; /* a copy of prec if [diouxX], 0 otherwise */
- int realsz; /* field size expanded by dprec, sign, etc */
- int size; /* size of converted field or string */
- int prsize; /* max size of printed field */
- const char *xdigs; /* digits for %[xX] conversion */
- BSDFmt_UIO uio; /* output information: summary */
- BSDFmt_IOV iov[BSDFMT_NIOV]; /* ... and individual io vectors */
- char buf[INT_CONV_BUF]; /* buffer with space for digits of uintmax_t */
- char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
- union arg *argtable; /* args, built due to positional arg */
- union arg statargtable [STATIC_ARG_TBL_SIZE];
- int nextarg; /* 1-based argument index */
-#ifndef _WIN32
- va_list orgap; /* original argument pointer */
-#endif
- char *convbuf = NULL; /* wide to multibyte conversion result */
- BSDFmt_StrBuf sbuf;
-
- /*
- * BEWARE, these `goto error' on error, and PAD uses `n'.
- */
-#define PRINT(ptr, len) { \
- iovp->iov_base = (ptr); \
- iovp->iov_len = (len) * sizeof (char); \
- uio.uio_resid += (len) * sizeof (char); \
- iovp++; \
- if (++uio.uio_iovcnt >= BSDFMT_NIOV) { \
- if (BSDFmt_SPrint(&sbuf, &uio)) \
- goto error; \
- iovp = iov; \
- } \
- }
-
-#define PAD(howmany, with) { \
- if ((n = (howmany)) > 0) { \
- while (n > PADSIZE) { \
- PRINT(with, PADSIZE); \
- n -= PADSIZE; \
- } \
- PRINT(with, n); \
- } \
- }
-
-#define PRINTANDPAD(p, ep, len, with) do { \
- n2 = (ep) - (p); \
- if (n2 > (len)) \
- n2 = (len); \
- if (n2 > 0) \
- PRINT((p), n2); \
- PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
- } while(0)
-
-#define FLUSH() { \
- if (uio.uio_resid && BSDFmt_SPrint(&sbuf, &uio)) \
- goto error; \
- uio.uio_iovcnt = 0; \
- iovp = iov; \
- }
-
- /*
- * Get the argument indexed by nextarg. If the argument table is
- * built, use it to get the argument. If its not, get the next
- * argument (and arguments must be gotten sequentially).
- */
-
-#define GETARG(type) \
- ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
- (nextarg++, va_arg(ap, type)))
-
- /*
- * To extend shorts properly, we need both signed and unsigned
- * argument extraction methods.
- */
-
-#define SARG() \
- (flags&LONGINT ? GETARG(long) : \
- flags&SHORTINT ? (long)(short)GETARG(int) : \
- flags&CHARINT ? (long)(signed char)GETARG(int) : \
- (long)GETARG(int))
-
-#define UARG() \
- (flags&LONGINT ? GETARG(u_long) : \
- flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
- flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
- (u_long)GETARG(u_int))
-
-#define SJARG() \
- (flags&INTMAXT ? GETARG(intmax_t) : \
- flags&SIZET ? (intmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
- (intmax_t)GETARG(long long))
-
-#define UJARG() \
- (flags&INTMAXT ? GETARG(uintmax_t) : \
- flags&SIZET ? (uintmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
- (uintmax_t)GETARG(unsigned long long))
-
- /*
- * Get * arguments, including the form *nn$. Preserve the nextarg
- * that the argument can be gotten once the type is determined.
- */
-
-#define GETASTER(val) \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- FIND_ARGUMENTS(); \
- nextarg = n2; \
- val = GETARG (int); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- val = GETARG (int); \
- }
-
- /*
- * Windows can't scan the args twice, so always build argtable.
- * Otherwise, do it when we see an n$ argument.
- */
-
-#ifndef _WIN32
- #define FIND_ARGUMENTS() \
- (argtable == NULL ? \
- (argtable = statargtable, \
- __find_arguments(fmt0, orgap, &argtable)) : \
- (void) 0)
-#else
- #define FIND_ARGUMENTS() \
- ASSERT(argtable != NULL)
-#endif
-
- xdigs = xdigs_lower;
- thousands_sep = '\0';
- grouping = NULL;
- convbuf = NULL;
-#if !defined(NO_FLOATING_POINT)
- dtoaresult = NULL;
-#ifdef __ANDROID__
- /*
- * Struct lconv is not working! For decimal_point,
- * using '.' instead is a workaround.
- */
- decimal_point = &dp;
-#endif
-#endif
-
- fmt = (char *)fmt0;
- nextarg = 1;
-#ifndef _WIN32
- argtable = NULL;
- va_copy(orgap, ap);
-#else
- argtable = statargtable;
- __find_arguments(fmt0, ap, &argtable);
-#endif
- uio.uio_iov = iovp = iov;
- uio.uio_resid = 0;
- uio.uio_iovcnt = 0;
- ret = 0;
-
- /*
- * Set up output string buffer structure.
- */
-
- sbuf.alloc = (*outbuf == NULL);
- sbuf.error = FALSE;
- sbuf.buf = *outbuf;
- sbuf.size = bufSize;
- sbuf.index = 0;
-
- /*
- * If asprintf(), allocate initial buffer based on format length.
- * Empty format only needs one byte. Otherwise, round up to multiple of 64.
- */
-
- if (sbuf.alloc) {
- size_t n = strlen(fmt0) + 1; // +1 for \0
-
- if (n > 1) {
- n = ROUNDUP(n, 64);
- }
- if ((sbuf.buf = malloc(n * sizeof (char))) == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- sbuf.size = n;
- }
-
- // shut compile up
-#if !defined(NO_FLOATING_POINT)
- expchar = 0;
- expsize = 0;
- lead = 0;
- ndig = 0;
- nseps = 0;
- nrepeats = 0;
-#endif
- ulval = 0;
- ujval = 0;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if ((n = fmt - cp) != 0) {
- if ((unsigned)ret + n > INT_MAX) {
- ret = EOF;
- goto error;
- }
- PRINT(cp, n);
- ret += n;
- }
- if (ch == '\0') {
- goto done;
- }
- fmt++; /* skip over '%' */
-
- flags = 0;
- dprec = 0;
- width = 0;
- prec = -1;
- sign = '\0';
- ox[1] = '\0';
-
- rflag: ch = *fmt++;
- reswitch: switch (ch) {
- case ' ':
- /*-
- * ``If the space and + flags both appear, the space flag will be
- * ignored.'' -- ANSI X3J11
- */
-
- if (!sign) {
- sign = ' ';
- }
- goto rflag;
- case '#':
- flags |= ALT;
- goto rflag;
- case '*':
- /*-
- * ``A negative field width argument is taken as a flag followed by
- * a positive field width.''-- ANSI X3J11
- *
- * They don't exclude field widths read from args.
- */
- GETASTER (width);
- if (width >= 0) {
- goto rflag;
- }
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '\'':
- flags |= GROUPING;
-#if !defined __ANDROID__
- thousands_sep = thousands_sepIn;
- grouping = groupingIn;
-#else
- /*
- * Struct lconv is not working! The code below is a workaround.
- */
- thousands_sep = ',';
-#endif
- /*
- * Grouping should not begin with 0, but it nevertheless does (see
- * bug 281072) and makes the formatting code behave badly, so we
- * fix it up.
- */
-
- if (grouping != NULL && *grouping == '\0') {
- static char g[] = { CHAR_MAX, '\0' };
-
- grouping = g;
- }
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- GETASTER (prec);
- goto rflag;
- }
- prec = 0;
- while (is_digit(ch)) {
- prec = 10 * prec + to_digit(ch);
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- /*-
- * ``Note that 0 is taken as a flag, not as the beginning of a
- * field width.'' -- ANSI X3J11
- */
-
- flags |= ZEROPAD;
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- if (ch == '$') {
- nextarg = n;
- FIND_ARGUMENTS();
- goto rflag;
- }
- width = n;
- goto reswitch;
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else {
- flags |= SHORTINT;
- }
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'I':
- /* could be I64 - long long int is 64bit */
- if (fmt[0] == '6' && fmt[1] == '4') {
- fmt += 2;
- flags |= LLONGINT;
- goto rflag;
- }
- /* could be I32 - normal int is 32bit */
- if (fmt[0] == '3' && fmt[1] == '2') {
- fmt += 2;
- /* flags |= normal integer - it is 32bit for all our targets */
- goto rflag;
- }
- /*
- * I alone - use Microsoft's semantic as size_t modifier. We do
- * not support glibc's semantic to use alternative digits.
- */
- flags |= SIZET;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'L':
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'Z':
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
- if (flags & LONGINT) {
- static const mbstate_t initial;
- mbstate_t mbs;
- size_t mbseqlen;
-
- mbs = initial;
- mbseqlen = wcrtomb(cp = buf, (wchar_t) GETARG(wint_t), &mbs);
- if (mbseqlen == (size_t) -1) {
- sbuf.error = TRUE;
- goto error;
- }
- size = (int) mbseqlen;
- } else {
- *(cp = buf) = GETARG(int);
- size = 1;
- }
- sign = '\0';
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- if (flags & INTMAX_SIZE) {
- ujval = SJARG();
- if ((intmax_t) ujval < 0) {
- ujval = -ujval;
- sign = '-';
- }
- } else {
- ulval = SARG();
- if ((long) ulval < 0) {
- ulval = -ulval;
- sign = '-';
- }
- }
- base = 10;
- goto number;
-
-#if !defined(NO_FLOATING_POINT)
- case 'e':
- case 'E':
- expchar = ch;
- if (prec < 0) { /* account for digit before decpt */
- prec = DEFPREC + 1;
- } else {
- prec++;
- }
- goto fp_begin;
- case 'f':
- case 'F':
- expchar = '\0';
- goto fp_begin;
- case 'g':
- case 'G':
- expchar = ch - ('g' - 'e');
- if (prec == 0) {
- prec = 1;
- }
- fp_begin:
- if (prec < 0) {
- prec = DEFPREC;
- }
- if (dtoaresult != NULL) {
- freedtoa(dtoaresult);
- }
- if (flags & LLONGINT) {
- fparg.ldbl = GETARG(long double);
-#if defined NO_LDTOA
- dtoaresult = NULL;
- /*
- * Below is to keep compiler happy
- */
- signflag = -1;
- expt = 0;
- dtoaend = NULL;
-#else
- dtoaresult = cp = ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
- &expt, &signflag, &dtoaend);
-#endif
- } else {
- fparg.dbl = GETARG(double);
-#if defined NO_DTOA
- dtoaresult = NULL;
- /*
- * Below is to keep compiler happy
- */
- signflag = -1;
- expt = 0;
- dtoaend = NULL;
-#else
- dtoaresult = cp = dtoa(fparg.dbl, expchar ? 2 : 3, prec,
- &expt, &signflag, &dtoaend);
-#endif
- }
-
- /* Our dtoa / ldtoa call strdup(), which can fail. PR319844 */
- if (dtoaresult == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
-
- flags |= FPT;
-
- if ((expt == 9999) ||
- ((Str_Strcasecmp(cp, "-inf") == 0) ||
- (Str_Strcasecmp(cp, "inf") == 0) ||
- (Str_Strcasecmp(cp, "nan") == 0))) {
- if (*cp == '-') {
- sign = '-';
- cp++;
- }
-
- cp = islower(ch) ? Str_ToLower(cp) : Str_ToUpper(cp);
-
- expt = INT_MAX;
- size = strlen(cp);
- break;
- }
-
- if (signflag) {
- sign = '-';
- }
-
- ndig = dtoaend - cp;
- if (ch == 'g' || ch == 'G') {
- if (expt > -4 && expt <= prec) {
- /* Make %[gG] smell like %[fF] */
- expchar = '\0';
- if (flags & ALT) {
- prec -= expt;
- } else {
- prec = ndig - expt;
- }
-
- if (prec < 0) {
- prec = 0;
- }
- } else {
- /*
- * Make %[gG] smell like %[eE], but trim trailing zeroes
- * if no # flag.
- */
-
- if (!(flags & ALT)) {
- prec = ndig;
- }
- }
- }
- if (expchar) {
- expsize = BSDFmt_Exponent(expstr, expt - 1, expchar);
- size = expsize + prec;
- if (prec > 1 || flags & ALT) {
- ++size;
- }
- } else {
- /* space for digits before decimal point */
- if (expt > 0) {
- size = expt;
- } else { /* "0" */
- size = 1;
- }
- /* space for decimal pt and following digits */
- if (prec || flags & ALT) {
- size += prec + 1;
- }
- if (grouping && expt > 0) {
- /* space for thousands' grouping */
- nseps = nrepeats = 0;
- lead = expt;
- while (*grouping != CHAR_MAX) {
- if (lead <= *grouping) {
- break;
- }
- lead -= *grouping;
- if (*(grouping + 1)) {
- nseps++;
- grouping++;
- } else {
- nrepeats++;
- }
- }
- size += nseps + nrepeats;
- } else {
- lead = expt;
- }
- }
- break;
-#endif /* !NO_FLOATING_POINT */
-
- case 'n':
- /*
- * Assignment-like behavior is specified if the value overflows or
- * is otherwise unrepresentable. C99 says to use `signed char'
- * for %hhn conversions.
- */
-
- if (flags & LLONGINT) {
- *GETARG(long long *) = ret;
- }
- else if (flags & SIZET) {
- *GETARG(size_t *) = (size_t)ret;
- }
- else if (flags & PTRDIFFT) {
- *GETARG(ptrdiff_t *) = ret;
- }
- else if (flags & INTMAXT) {
- *GETARG(intmax_t *) = ret;
- }
- else if (flags & LONGINT) {
- *GETARG(long *) = ret;
- }
- else if (flags & SHORTINT) {
- *GETARG(short *) = ret;
- }
- else if (flags & CHARINT) {
- *GETARG(signed char *) = ret;
- } else {
- *GETARG(int *) = ret;
- }
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- if (flags & INTMAX_SIZE) {
- ujval = UJARG();
- } else {
- ulval = UARG();
- }
- base = 8;
- goto nosign;
- case 'p':
- /*-
- * ``The argument shall be a pointer to void. The value of the
- * pointer is converted to a sequence of printable characters, in
- * an implementation- defined manner.'' -- ANSI X3J11
- */
-
- ujval = (uintmax_t)(uintptr_t) GETARG(void *);
- base = 16;
- xdigs = xdigs_upper;
- flags = flags | INTMAXT;
- /*
- * PR 103201
- * VisualC sscanf doesn't grok '0x', so prefix zeroes.
- */
-// ox[1] = 'x';
- goto nosign;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (flags & LONGINT) {
- wchar_t *wcp;
-
- /* Argument is wchar_t * */
- if (convbuf != NULL) {
- free(convbuf);
- convbuf = NULL;
- }
- if ((wcp = GETARG(wchar_t *)) == NULL) {
- cp = "(null)";
- } else {
- convbuf = BSDFmt_WCharToUTF8(wcp, prec);
- if (convbuf == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- cp = convbuf;
- }
- } else if ((cp = GETARG(char *)) == NULL) {
- /* Argument is char * */
- cp = "(null)";
- }
-
- if (prec >= 0) {
- /*
- * can't use strlen; can only look for the NUL in the first
- * `prec' characters, and strlen() will go further.
- */
-
- char *p = memchr(cp, 0, (size_t)prec);
-
- if (p == NULL) {
- size = prec;
- } else {
- size = p - cp;
-
- if (size > prec) {
- size = prec;
- }
- }
- size = CodeSet_Utf8FindCodePointBoundary(cp, size);
- } else {
- size = strlen(cp);
- }
- sign = '\0';
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 10;
- goto nosign;
- case 'X':
- xdigs = xdigs_upper;
- goto hex;
- case 'x':
- xdigs = xdigs_lower;
- hex:
- if (flags & INTMAX_SIZE) {
- ujval = UJARG();
- } else {
- ulval = UARG();
- }
- base = 16;
- /* leading 0x/X only if non-zero */
- if (flags & ALT && (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) {
- ox[1] = ch;
- }
-
- flags &= ~GROUPING;
- /* unsigned conversions */
- nosign: sign = '\0';
- /*-
- * ``... diouXx conversions ... if a precision is specified, the
- * 0 flag will be ignored.'' -- ANSI X3J11
- */
- number: if ((dprec = prec) >= 0) {
- flags &= ~ZEROPAD;
- }
-
- /*-
- * ``The result of converting a zero value with an explicit
- * precision of zero is no characters.'' -- ANSI X3J11
- *
- * ``The C Standard is clear enough as is. The call printf("%#.0o", 0)
- * should print 0.'' -- Defect Report #151
- */
-
- cp = buf + INT_CONV_BUF;
- if (flags & INTMAX_SIZE) {
- if (ujval != 0 || prec != 0 ||
- (flags & ALT && base == 8)) {
- cp = BSDFmt_UJToA(ujval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- }
- } else {
- if (ulval != 0 || prec != 0 ||
- (flags & ALT && base == 8)) {
- cp = __ultoa(ulval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- }
- }
- size = buf + INT_CONV_BUF - cp;
- if (size > INT_CONV_BUF) { /* should never happen */
- abort();
- }
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0') {
- goto done;
- }
- /* pretend it was %c with argument ch */
- cp = buf;
- *cp = ch;
- size = 1;
- sign = '\0';
- break;
- }
-
- /*
- * All reasonable formats wind up here. At this point, `cp' points to
- * a string which (if not flags&LADJUST) should be padded out to `width'
- * places. If flags&ZEROPAD, it should first be prefixed by any sign
- * or other prefix; otherwise, it should be blank padded before the
- * prefix is emitted. After any left-hand padding and prefixing, emit
- * zeroes required by a decimal [diouxX] precision, then print the
- * string proper, then emit zeroes required by any leftover floating
- * precision; finally, if LADJUST, pad with blanks.
- *
- * Compute actual size, so we know how much to pad. size excludes
- * decimal prec; realsz includes it.
- */
-
- realsz = dprec > size ? dprec : size;
- if (sign) {
- realsz++;
- }
- if (ox[1]) {
- realsz += 2;
- }
-
- prsize = width > realsz ? width : realsz;
- if ((unsigned)ret + prsize > INT_MAX) {
- ret = EOF;
- goto error;
- }
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST | ZEROPAD)) == 0) {
- PAD(width - realsz, blanks);
- }
-
- /* prefix */
- if (sign) {
- PRINT(&sign, 1);
- }
-
-#if !defined(NO_FLOATING_POINT)
- /* NAN, INF and -INF */
- if ((flags & FPT) && (expt == INT_MAX)) {
- PRINT(cp, size);
- goto skip;
- }
-#endif
-
- if (ox[1]) { /* ox[1] is either x, X, or \0 */
- ox[0] = '0';
- PRINT(ox, 2);
- }
-
- /* right-adjusting zero padding */
- if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
- PAD(width - realsz, zeroes);
- }
-
- /* leading zeroes from decimal precision */
- PAD(dprec - size, zeroes);
-
- /* the string or number proper */
- if (flags & FPT) { /* glue together f_p fragments */
-#if defined(NO_FLOATING_POINT)
- NOT_IMPLEMENTED();
-#else
- if (expchar) { /* %[fF] or sufficiently short %[gG] */
- if (prec > 1 || flags & ALT) {
- buf[0] = *cp++;
- buf[1] = *decimal_point;
- PRINT(buf, 2);
- if (ndig > 0) {
- PRINT(cp, ndig - 1);
- PAD(prec - ndig, zeroes);
- } else {
- PAD(prec - ndig - 1, zeroes);
- }
- } else { /* XeYYY */
- PRINT(cp, 1);
- }
-
- PRINT(expstr, expsize);
- } else { /* %[eE] or sufficiently long %[gG] */
- if (expt <= 0) {
- PRINT(zeroes, 1);
- if (prec || flags & ALT) {
- PRINT(decimal_point, 1);
- }
-
- PAD(-expt, zeroes);
- /* already handled initial 0's */
- prec += expt;
- } else {
- PRINTANDPAD(cp, dtoaend, lead, zeroes);
- cp += lead;
- if (grouping) {
- while (nseps > 0 || nrepeats > 0) {
- if (nrepeats > 0) {
- nrepeats--;
- } else {
- grouping--;
- nseps--;
- }
- PRINT(&thousands_sep, 1);
- PRINTANDPAD(cp, dtoaend, *grouping, zeroes);
- cp += *grouping;
- }
- if (cp > dtoaend) {
- cp = dtoaend;
- }
- }
- if (prec || flags & ALT) {
- PRINT(decimal_point, 1);
- }
- }
- PRINTANDPAD(cp, dtoaend, prec, zeroes);
- }
-#endif
- } else {
- PRINT(cp, size);
- }
-
-skip:
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST) {
- PAD(width - realsz, blanks);
- }
-
- /* finally, adjust ret */
- ret += prsize;
-
- FLUSH(); /* copy out the I/O vectors */
- }
-
-done:
- FLUSH();
-
- /*
- * Always null terminate, unless buffer is size 0.
- */
-
- ASSERT(!sbuf.error && ret >= 0);
- if (sbuf.size <= 0) {
- ASSERT(!sbuf.alloc);
- } else {
- ASSERT(sbuf.index < sbuf.size);
- sbuf.buf[sbuf.index] = '\0';
- }
-
-error:
-#ifndef _WIN32
- va_end(orgap);
-#endif
-#if !defined(NO_FLOATING_POINT)
- if (dtoaresult != NULL) {
- freedtoa(dtoaresult);
- }
-#endif
- if (convbuf != NULL) {
- free(convbuf);
- convbuf = NULL;
- }
- if (sbuf.error) {
- ret = EOF;
- }
- if ((argtable != NULL) && (argtable != statargtable)) {
- free (argtable);
- }
-
- // return allocated buffer on success, free it on failure
- if (sbuf.alloc) {
- if (ret < 0) {
- free(sbuf.buf);
- } else {
- *outbuf = sbuf.buf;
- }
- }
-
- return (ret);
- /* NOTREACHED */
-
-#undef PRINT
-#undef PAD
-#undef PRINTANDPAD
-#undef FLUSH
-#undef GETARG
-#undef SARG
-#undef SJARG
-#undef UARG
-#undef UJARG
-#undef GETASTER
-#undef FIND_ARGUMENTS
-}
-
-int
-bsd_vsnprintf_c_locale(char **outbuf,
- size_t bufSize,
- const char *fmt0,
- va_list ap)
-{
- char thousands_sep;
- char *decimal_point;
- static char dp = '.';
-
- /*
- * Perform a "%f" conversion always using the locale associated
- * with the C locale - "," for thousands, '.' for decimal point.
- */
-
- thousands_sep = ',';
- decimal_point = &dp;
-
- return bsd_vsnprintf_core(outbuf, NULL, thousands_sep, decimal_point,
- bufSize, fmt0, ap);
-}
-
-int
-bsd_vsnprintf(char **outbuf,
- size_t bufSize,
- const char *fmt0,
- va_list ap)
-{
- char *grouping;
- char thousands_sep;
- char *decimal_point;
-
-#if defined(__ANDROID__)
- static char dp = '.';
-
- /*
- * Struct lconv is not working! The code below is a workaround.
- */
- grouping = NULL;
- thousands_sep = ',';
- decimal_point = &dp;
-#else
- grouping = localeconv()->grouping;
- thousands_sep = *(localeconv()->thousands_sep);
- decimal_point = localeconv()->decimal_point;
-#endif
-
- return bsd_vsnprintf_core(outbuf, grouping, thousands_sep, decimal_point,
- bufSize, fmt0, ap);
-}
-
-/*
- * Find all arguments when a positional parameter is encountered. Returns a
- * table, indexed by argument number, of pointers to each arguments. The
- * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
- * It will be replaces with a malloc-ed one if it overflows.
- */
-
-static void
-__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
-{
- char *fmt; /* format string */
- int ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- char *cp; /* handy char pointer (short term usage) */
- int flags; /* flags as above */
- enum typeid *typetable; /* table of types */
- enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
- int tablesize; /* current size of type table */
- int tablemax; /* largest used index in table */
- int nextarg; /* 1-based argument index */
-
- /*
- * Add an argument type to the table, expanding if necessary.
- */
-#define ADDTYPE(type) \
- ((nextarg >= tablesize) ? \
- __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
- (nextarg > tablemax) ? tablemax = nextarg : 0, \
- typetable[nextarg++] = type)
-
-#define ADDSARG() \
- ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
- ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
- ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
- ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
- ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
-
-#define ADDUARG() \
- ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
- ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
- ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
- ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
- ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
-
- /*
- * Add * arguments to the type array.
- */
-#define ADDASTER() \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- nextarg = n2; \
- ADDTYPE (T_INT); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- ADDTYPE (T_INT); \
- }
- fmt = (char *)fmt0;
- typetable = stattypetable;
- tablesize = STATIC_ARG_TBL_SIZE;
- tablemax = 0;
- nextarg = 1;
- for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
- typetable[n] = T_UNUSED;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
-
- rflag: ch = *fmt++;
- reswitch: switch (ch) {
- case ' ':
- case '#':
- goto rflag;
- case '*':
- ADDASTER ();
- goto rflag;
- case '-':
- case '+':
- case '\'':
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- ADDASTER ();
- goto rflag;
- }
- while (is_digit(ch)) {
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- if (ch == '$') {
- nextarg = n;
- goto rflag;
- }
- goto reswitch;
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'I':
- /* could be I64 - long long int is 64bit */
- if (fmt[0] == '6' && fmt[1] == '4') {
- fmt += 2;
- flags |= LLONGINT;
- goto rflag;
- }
- /* could be I32 - normal int is 32bit */
- if (fmt[0] == '3' && fmt[1] == '2') {
- fmt += 2;
- /* flags |= normal integer - it is 32bit for all our targets */
- goto rflag;
- }
- /*
- * I alone - use Microsoft's semantic as size_t modifier. We do
- * not support glibc's semantic to use alternative digits.
- */
- flags |= SIZET;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'L':
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'Z':
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
- if (flags & LONGINT)
- ADDTYPE(T_WINT);
- else
- ADDTYPE(T_INT);
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- ADDSARG();
- break;
-#if !defined(NO_FLOATING_POINT)
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- if (flags & LLONGINT)
- ADDTYPE(T_LONG_DOUBLE);
- else
- ADDTYPE(T_DOUBLE);
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- if (flags & INTMAXT)
- ADDTYPE(TP_INTMAXT);
- else if (flags & PTRDIFFT)
- ADDTYPE(TP_PTRDIFFT);
- else if (flags & SIZET)
- ADDTYPE(TP_SIZET);
- else if (flags & LLONGINT)
- ADDTYPE(TP_LLONG);
- else if (flags & LONGINT)
- ADDTYPE(TP_LONG);
- else if (flags & SHORTINT)
- ADDTYPE(TP_SHORT);
- else if (flags & CHARINT)
- ADDTYPE(TP_SCHAR);
- else
- ADDTYPE(TP_INT);
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- ADDUARG();
- break;
- case 'p':
- ADDTYPE(TP_VOID);
- break;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (flags & LONGINT)
- ADDTYPE(TP_WCHAR);
- else
- ADDTYPE(TP_CHAR);
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- case 'X':
- case 'x':
- ADDUARG();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- break;
- }
- }
- done:
- /*
- * Build the argument table.
- */
- if (tablemax >= STATIC_ARG_TBL_SIZE) {
- *argtable = (union arg *)
- malloc (sizeof (union arg) * (tablemax + 1));
- }
-
- (*argtable) [0].intarg = 0;
- for (n = 1; n <= tablemax; n++) {
- switch (typetable [n]) {
- case T_UNUSED: /* whoops! */
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case TP_SCHAR:
- (*argtable) [n].pschararg = va_arg (ap, signed char *);
- break;
- case TP_SHORT:
- (*argtable) [n].pshortarg = va_arg (ap, short *);
- break;
- case T_INT:
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case T_U_INT:
- (*argtable) [n].uintarg = va_arg (ap, unsigned int);
- break;
- case TP_INT:
- (*argtable) [n].pintarg = va_arg (ap, int *);
- break;
- case T_LONG:
- (*argtable) [n].longarg = va_arg (ap, long);
- break;
- case T_U_LONG:
- (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
- break;
- case TP_LONG:
- (*argtable) [n].plongarg = va_arg (ap, long *);
- break;
- case T_LLONG:
- (*argtable) [n].longlongarg = va_arg (ap, long long);
- break;
- case T_U_LLONG:
- (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
- break;
- case TP_LLONG:
- (*argtable) [n].plonglongarg = va_arg (ap, long long *);
- break;
- case T_PTRDIFFT:
- (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
- break;
- case TP_PTRDIFFT:
- (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
- break;
- case T_SIZET:
- (*argtable) [n].sizearg = va_arg (ap, size_t);
- break;
- case TP_SIZET:
- (*argtable) [n].psizearg = va_arg (ap, size_t *);
- break;
- case T_INTMAXT:
- (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
- break;
- case T_UINTMAXT:
- (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
- break;
- case TP_INTMAXT:
- (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
- break;
-#if !defined(NO_FLOATING_POINT)
- case T_DOUBLE:
- (*argtable) [n].doublearg = va_arg (ap, double);
- break;
- case T_LONG_DOUBLE:
- (*argtable) [n].longdoublearg = va_arg (ap, long double);
- break;
-#endif
- case TP_CHAR:
- (*argtable) [n].pchararg = va_arg (ap, char *);
- break;
- case TP_VOID:
- (*argtable) [n].pvoidarg = va_arg (ap, void *);
- break;
- case T_WINT:
- (*argtable) [n].wintarg = va_arg (ap, wint_t);
- break;
- case TP_WCHAR:
- (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
- break;
- }
- }
-
- if ((typetable != NULL) && (typetable != stattypetable))
- free (typetable);
-
-#undef ADDTYPE
-#undef ADDSARG
-#undef ADDUARG
-#undef ADDASTER
-}
-
-/*
- * Increase the size of the type table.
- */
-static void
-__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
-{
- enum typeid *const oldtable = *typetable;
- const int oldsize = *tablesize;
- enum typeid *newtable;
- int n, newsize = oldsize * 2;
-
- if (newsize < nextarg + 1) {
- newsize = nextarg + 1;
- }
-
- if (oldsize == STATIC_ARG_TBL_SIZE) {
- if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) {
- abort(); /* XXX handle better */
- }
-
- memmove(newtable, oldtable, oldsize * sizeof(enum typeid));
- } else {
- newtable = realloc(oldtable, newsize * sizeof(enum typeid));
-
- if (newtable == NULL) {
- abort(); /* XXX handle better */
- }
- }
- for (n = oldsize; n < newsize; n++) {
- newtable[n] = T_UNUSED;
- }
-
- *typetable = newtable;
- *tablesize = newsize;
-}
-
-
-#if !defined(NO_FLOATING_POINT)
-int
-BSDFmt_Exponent(char *p0, int exp, int fmtch)
-{
- char *p, *t;
- char expbuf[MAXEXPDIG];
-
- p = p0;
- *p++ = fmtch;
- if (exp < 0) {
- exp = -exp;
- *p++ = '-';
- } else {
- *p++ = '+';
- }
-
- t = expbuf + MAXEXPDIG;
-
- if (exp < 10) {
- *p++ = '0';
- }
-
-// See PR 704706: POSIX specifies that exponents < 100 only have 2 digits
-// if (exp < 100) {
-// *p++ = '0';
-// }
-
- if (exp > 9) {
- do {
- *--t = to_char(exp % 10);
- } while ((exp /= 10) > 9);
-
- *--t = to_char(exp);
-
- for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
- } else {
- *p++ = to_char(exp);
- }
-
- return (p - p0);
-}
-#endif /* !NO_FLOATING_POINT */
-
-#endif /* !STR_NO_WIN32_LIBS|*BSD */
+++ /dev/null
-/* **********************************************************
- * Copyright 2006 VMware, Inc. All rights reserved.
- * **********************************************************/
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * 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.
- */
-/*
- * Note - this code originated as the file vfwprintf.c in the FreeBSD
- * source code, location src/lib/libc/stdio/vfwprintf.c, revision
- * 1.24. It has been borrowed and modified to act like vsnwprintf
- * instead. See bsd_output.h for more.
- *
- * If you care to compare, the original is checked into this directory
- * as bsd_vsnwprintf_orig.c.
- */
-
-#if !defined(STR_NO_WIN32_LIBS) && !defined(__FreeBSD__) \
- && !defined(__OpenBSD__) && !defined(__NetBSD__)
-
-/*
- * Actual wprintf innards.
- */
-
-#include <ctype.h>
-#include <limits.h>
-#include <locale.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "vmware.h"
-#include "bsd_output_int.h"
-#include "msgfmt.h"
-#include "convertutf.h"
-
-#if defined(__ANDROID__)
-/*
- * Android doesn't support dtoa() or ldtoa().
- */
-#define NO_DTOA
-#define NO_LDTOA
-#endif
-
-typedef struct StrBuf {
- Bool alloc;
- Bool error;
- wchar_t *buf;
- size_t size;
- size_t index;
-} StrBuf;
-
-static int __sfvwrite(StrBuf *sbuf, BSDFmt_UIO *uio);
-static int __sprint(StrBuf *sbuf, BSDFmt_UIO *uio);
-static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int,
- char, const char *);
-static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int,
- char, const char *);
-static wchar_t *BSDFmt_UTF8ToWChar(const char *, int);
-static void __find_arguments(const wchar_t *, va_list, union arg **);
-static void __grow_type_table(int, enum typeid **, int *);
-
-static Bool isLenientConversion = TRUE;
-
-static int
-__sfvwrite(StrBuf *sbuf, BSDFmt_UIO *uio)
-{
- int i;
- BSDFmt_IOV *siov;
-
- /*
- * If aswprintf(), then grow the buffer as necessary.
- */
-
- if (sbuf->alloc) {
- size_t n = sbuf->index + uio->uio_resid + 1; // +1 for \0
- if (n > sbuf->size) {
- wchar_t *p;
- ASSERT(sbuf->size > 0);
- n = ROUNDUP(n, sbuf->size);
- if ((p = realloc(sbuf->buf, n * sizeof(wchar_t))) == NULL) {
- sbuf->error = TRUE;
- return 1;
- }
- sbuf->buf = p;
- sbuf->size = n;
- }
- }
-
- for (i = 0, siov = uio->uio_iov; i < uio->uio_iovcnt; i++, siov++) {
- int numToWrite;
-
- /*
- * Overflowing the buffer is not an error.
- * We just silently truncate because that's what snprintf() does.
- *
- * Always leave space for null termination.
- */
-
- numToWrite = sbuf->size - sbuf->index - 1; // -1 for \0
- if (numToWrite > siov->iov_len) {
- numToWrite = siov->iov_len;
- }
-
- memcpy(sbuf->buf + sbuf->index, siov->iov_base,
- numToWrite * sizeof(wchar_t));
- sbuf->index += numToWrite;
- }
-
- return 0;
-}
-
-/*
- * Flush out all the vectors defined by the given uio,
- * then reset it so that it can be reused.
- */
-static int
-__sprint(StrBuf *sbuf, BSDFmt_UIO *uio)
-{
- int err;
-
- if (uio->uio_resid == 0) {
- uio->uio_iovcnt = 0;
- return (0);
- }
- err = __sfvwrite(sbuf, uio);
- uio->uio_resid = 0;
- uio->uio_iovcnt = 0;
- return err;
-}
-
-/*
- * Convert an unsigned long to ASCII for printf purposes, returning
- * a pointer to the first character of the string representation.
- * Octal numbers can be forced to have a leading zero; hex numbers
- * use the given digits.
- */
-static wchar_t *
-__ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs,
- int needgrp, char thousep, const char *grp)
-{
- wchar_t *cp = endp;
- long sval;
- int ndig;
-
- /*
- * Handle the three cases separately, in the hope of getting
- * better/faster code.
- */
- switch (base) {
- case 10:
- if (val < 10) { /* many numbers are 1 digit */
- *--cp = to_char(val);
- return (cp);
- }
- ndig = 0;
- /*
- * On many machines, unsigned arithmetic is harder than
- * signed arithmetic, so we do at most one unsigned mod and
- * divide; this is sufficient to reduce the range of
- * the incoming value to where signed arithmetic works.
- */
- if (val > LONG_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = val / 10;
- } else
- sval = val;
- do {
- *--cp = to_char(sval % 10);
- ndig++;
- /*
- * If (*grp == CHAR_MAX) then no more grouping
- * should be performed.
- */
- if (needgrp && ndig == *grp && *grp != CHAR_MAX
- && sval > 9) {
- *--cp = thousep;
- ndig = 0;
- /*
- * If (*(grp+1) == '\0') then we have to
- * use *grp character (last grouping rule)
- * for all next cases
- */
- if (*(grp+1) != '\0')
- grp++;
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
- if (octzero && *cp != '0')
- *--cp = '0';
- break;
-
- case 16:
- do {
- *--cp = xdigs[val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default: /* oops */
- abort();
- }
- return (cp);
-}
-
-/* Identical to __ultoa, but for intmax_t. */
-static wchar_t *
-__ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero,
- const char *xdigs, int needgrp, char thousep, const char *grp)
-{
- wchar_t *cp = endp;
- intmax_t sval;
- int ndig;
-
- /* quick test for small values; __ultoa is typically much faster */
- /* (perhaps instead we should run until small, then call __ultoa?) */
- if (val <= ULONG_MAX)
- return (__ultoa((u_long)val, endp, base, octzero, xdigs,
- needgrp, thousep, grp));
- switch (base) {
- case 10:
- if (val < 10) {
- *--cp = to_char(val % 10);
- return (cp);
- }
- ndig = 0;
- if (val > INTMAX_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = val / 10;
- } else
- sval = val;
- do {
- *--cp = to_char(sval % 10);
- ndig++;
- /*
- * If (*grp == CHAR_MAX) then no more grouping
- * should be performed.
- */
- if (needgrp && *grp != CHAR_MAX && ndig == *grp
- && sval > 9) {
- *--cp = thousep;
- ndig = 0;
- /*
- * If (*(grp+1) == '\0') then we have to
- * use *grp character (last grouping rule)
- * for all next cases
- */
- if (*(grp+1) != '\0')
- grp++;
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
- if (octzero && *cp != '0')
- *--cp = '0';
- break;
-
- case 16:
- do {
- *--cp = xdigs[val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default:
- abort();
- }
- return (cp);
-}
-
-
-/*
- * Convert a UTF-8 string argument to a wide-character string
- * representation. If not -1, 'prec' specifies the maximum number of
- * wide characters to output. The returned string is always NUL-terminated,
- * even if that results in the string exceeding 'prec' characters.
- */
-wchar_t *
-BSDFmt_UTF8ToWChar(const char *arg, // IN
- int prec) // IN
-{
- ConversionResult cres;
- const char *sourceStart, *sourceEnd;
- wchar_t *targStart, *targEnd;
- wchar_t *targ = NULL;
-
- /*
- * targSize and sourceSize are measured in wchar_t units, excluding NUL.
- */
- size_t targSize;
- size_t sourceSize = strlen(arg);
-
- ASSERT(prec == -1 || prec >= 0);
-
- targSize = sourceSize;
- if (prec >= 0) {
- targSize = MIN(targSize, prec);
- }
-
- while (TRUE) {
- /*
- * Pad by 1 because we need to NUL-terminate.
- */
- wchar_t *oldTarg = targ;
- targ = realloc(oldTarg, (targSize + 1) * sizeof *targ);
- if (!targ) {
- free(oldTarg);
- goto exit;
- }
-
- targStart = targ;
- targEnd = targStart + targSize;
- sourceStart = arg;
- sourceEnd = sourceStart + sourceSize;
-
- if (2 == sizeof(wchar_t)) {
- cres = ConvertUTF8toUTF16((const UTF8 **) &sourceStart,
- (const UTF8 *) sourceEnd,
- (UTF16 **) &targStart,
- (UTF16 *) targEnd,
- isLenientConversion);
- } else if (4 == sizeof(wchar_t)) {
- cres = ConvertUTF8toUTF32((const UTF8 **) &sourceStart,
- (const UTF8 *) sourceEnd,
- (UTF32 **) &targStart,
- (UTF32 *) targEnd,
- isLenientConversion);
- } else {
- NOT_IMPLEMENTED();
- }
-
- if (targetExhausted == cres) {
- if (targSize == prec) {
- /*
- * We've got all the caller wants.
- */
- break;
- } else {
- /*
- * Grow the buffer.
- */
- ASSERT(FALSE);
- targSize *= 2;
- if (prec >= 0) {
- targSize = MIN(targSize, prec);
- }
- }
- } else if ((sourceExhausted == cres) ||
- (sourceIllegal == cres)) {
- /*
- * If lenient, the API converted all it could, so just
- * proceed, otherwise, barf.
- */
- if (isLenientConversion) {
- break;
- } else {
- free(targ);
- targ = NULL;
- goto exit;
- }
- } else if (conversionOK == cres) {
- break;
- } else {
- NOT_IMPLEMENTED();
- }
- }
-
- /*
- * Success, NUL-terminate. (The API updated targStart for us).
- */
- ASSERT(targStart <= targEnd);
- *targStart = L'\0';
-
- exit:
- return targ;
-}
-
-
-#ifndef NO_FLOATING_POINT
-
-static int exponent(wchar_t *, int, wchar_t);
-
-#endif /* !NO_FLOATING_POINT */
-
-int
-bsd_vsnwprintf(wchar_t **outBuf, size_t bufSize, const wchar_t *fmt0,
- va_list ap)
-{
- wchar_t *fmt; /* format string */
- wchar_t ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- wchar_t *cp; /* handy char pointer (short term usage) */
- BSDFmt_IOV *iovp; /* for PRINT macro */
- int flags; /* flags as above */
- int ret; /* return value accumulator */
- int width; /* width from format (%8d), or 0 */
- int prec; /* precision from format; <0 for N/A */
- wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
- wchar_t thousands_sep; /* locale specific thousands separator */
- const char *grouping; /* locale specific numeric grouping rules */
-#ifndef NO_FLOATING_POINT
- /*
- * We can decompose the printed representation of floating
- * point numbers into several parts, some of which may be empty:
- *
- * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
- * A B ---C--- D E F
- *
- * A: 'sign' holds this value if present; '\0' otherwise
- * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
- * C: cp points to the string MMMNNN. Leading and trailing
- * zeros are not in the string and must be added.
- * D: expchar holds this character; '\0' if no exponent, e.g. %f
- * F: at least two digits for decimal, at least one digit for hex
- */
- char *decimal_point; /* locale specific decimal point */
- int signflag; /* true if float is negative */
- union { /* floating point arguments %[aAeEfFgG] */
- double dbl;
- long double ldbl;
- } fparg;
- int expt; /* integer value of exponent */
- char expchar; /* exponent character: [eEpP\0] */
- char *dtoaend; /* pointer to end of converted digits */
- int expsize; /* character count for expstr */
- int lead; /* sig figs before decimal or group sep */
- int ndig; /* actual number of digits returned by dtoa */
- wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
- char *dtoaresult; /* buffer allocated by dtoa */
- int nseps; /* number of group separators with ' */
- int nrepeats; /* number of repeats of the last group */
-#endif
- u_long ulval; /* integer arguments %[diouxX] */
- uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
- int base; /* base for [diouxX] conversion */
- int dprec; /* a copy of prec if [diouxX], 0 otherwise */
- int realsz; /* field size expanded by dprec, sign, etc */
- int size; /* size of converted field or string */
- int prsize; /* max size of printed field */
- const char *xdigs; /* digits for [xX] conversion */
- BSDFmt_UIO uio; /* output information: summary */
- BSDFmt_IOV iov[BSDFMT_NIOV]; /* ... and individual io vectors */
- wchar_t buf[INT_CONV_BUF]; /* buffer with space for digits of uintmax_t */
- wchar_t ox[2]; /* space for 0x hex-prefix */
- union arg *argtable; /* args, built due to positional arg */
- union arg statargtable [STATIC_ARG_TBL_SIZE];
- int nextarg; /* 1-based argument index */
- wchar_t *convbuf; /* multibyte to wide conversion result */
-#ifndef _WIN32
- va_list orgap;
-#endif
- StrBuf sbuf;
-
- /*
- * Choose PADSIZE to trade efficiency vs. size. If larger printf
- * fields occur frequently, increase PADSIZE and make the initialisers
- * below longer.
- */
-#define PADSIZE 16 /* pad chunk size */
- static wchar_t blanks[PADSIZE] =
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
- static wchar_t zeroes[PADSIZE] =
- {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
-
- static const char xdigs_lower[16] = "0123456789abcdef";
- static const char xdigs_upper[16] = "0123456789ABCDEF";
-
- /*
- * BEWARE, these `goto error' on error, PRINT uses `n2' and
- * PAD uses `n'.
- */
- /*
- * BEWARE, these `goto error' on error, and PAD uses `n'.
- */
-#define PRINT(ptr, len) { \
- iovp->iov_base = (ptr); \
- iovp->iov_len = len; \
- uio.uio_resid += len; \
- iovp++; \
- if (++uio.uio_iovcnt >= BSDFMT_NIOV) { \
- if (__sprint(&sbuf, &uio)) \
- goto error; \
- iovp = iov; \
- } \
- }
-#define PAD(howmany, with) do { \
- if ((n = (howmany)) > 0) { \
- while (n > PADSIZE) { \
- PRINT(with, PADSIZE); \
- n -= PADSIZE; \
- } \
- PRINT(with, n); \
- } \
- } while (0)
-#define PRINTANDPAD(p, ep, len, with) do { \
- n2 = (ep) - (p); \
- if (n2 > (len)) \
- n2 = (len); \
- if (n2 > 0) \
- PRINT((p), n2); \
- PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
- } while(0)
-#define FLUSH() { \
- if (uio.uio_resid && __sprint(&sbuf, &uio)) \
- goto error; \
- uio.uio_iovcnt = 0; \
- iovp = iov; \
- }
-
- /*
- * Get the argument indexed by nextarg. If the argument table is
- * built, use it to get the argument. If its not, get the next
- * argument (and arguments must be gotten sequentially).
- */
-#define GETARG(type) \
- ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
- (nextarg++, va_arg(ap, type)))
-
- /*
- * To extend shorts properly, we need both signed and unsigned
- * argument extraction methods.
- */
-#define SARG() \
- (flags&LONGINT ? GETARG(long) : \
- flags&SHORTINT ? (long)(short)GETARG(int) : \
- flags&CHARINT ? (long)(signed char)GETARG(int) : \
- (long)GETARG(int))
-#define UARG() \
- (flags&LONGINT ? GETARG(u_long) : \
- flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
- flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
- (u_long)GETARG(u_int))
-#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
-#define SJARG() \
- (flags&INTMAXT ? GETARG(intmax_t) : \
- flags&SIZET ? (intmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
- (intmax_t)GETARG(long long))
-#define UJARG() \
- (flags&INTMAXT ? GETARG(uintmax_t) : \
- flags&SIZET ? (uintmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
- (uintmax_t)GETARG(unsigned long long))
-
- /*
- * Get * arguments, including the form *nn$. Preserve the nextarg
- * that the argument can be gotten once the type is determined.
- */
-#define GETASTER(val) \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- nextarg = n2; \
- val = GETARG (int); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- val = GETARG (int); \
- }
-
-
- /*
- * Windows can't scan the args twice, so always build argtable.
- * Otherwise, do it when we see an n$ argument.
- */
-
-#ifndef _WIN32
- #define FIND_ARGUMENTS() \
- (argtable == NULL ? \
- (argtable = statargtable, \
- __find_arguments(fmt0, orgap, &argtable)) : \
- (void) 0)
-#else
- #define FIND_ARGUMENTS() \
- ASSERT(argtable != NULL)
-#endif
-
- xdigs = xdigs_lower;
- thousands_sep = L'\0';
- grouping = NULL;
-#ifndef NO_FLOATING_POINT
- decimal_point = localeconv()->decimal_point;
-#endif
- convbuf = NULL;
-
- fmt = (wchar_t *)fmt0;
- argtable = NULL;
- nextarg = 1;
- argtable = statargtable;
-#ifndef _WIN32
- argtable = NULL;
- va_copy(orgap, ap);
-#else
- argtable = statargtable;
- __find_arguments (fmt0, ap, &argtable);
-#endif
- uio.uio_iov = iovp = iov;
- uio.uio_resid = 0;
- uio.uio_iovcnt = 0;
- ret = 0;
-
- /*
- * Set up output string buffer structure.
- */
-
- sbuf.alloc = *outBuf == NULL;
- sbuf.error = FALSE;
- sbuf.buf = *outBuf;
- sbuf.size = bufSize;
- sbuf.index = 0;
-
- /*
- * If aswprintf(), allocate initial buffer based on format length.
- * Empty format only needs one byte.
- * Otherwise, round up to multiple of 64.
- */
-
- if (sbuf.alloc) {
- size_t n = wcslen(fmt0) + 1; // +1 for \0
- if (n > 1) {
- n = ROUNDUP(n, 64);
- }
- if ((sbuf.buf = malloc(n * sizeof (wchar_t))) == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- sbuf.size = n;
- }
-
- // shut compile up
-#ifndef NO_FLOATING_POINT
- expchar = 0;
- expsize = 0;
- lead = 0;
- ndig = 0;
- nseps = 0;
- nrepeats = 0;
-#endif
- ulval = 0;
- ujval = 0;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if ((n = fmt - cp) != 0) {
- if ((unsigned)ret + n > INT_MAX) {
- ret = EOF;
- goto error;
- }
- PRINT(cp, n);
- ret += n;
- }
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
- dprec = 0;
- width = 0;
- prec = -1;
- sign = '\0';
- ox[1] = '\0';
-
- rflag: ch = *fmt++;
- reswitch: switch (ch) {
- case ' ':
- /*-
- * ``If the space and + flags both appear, the space
- * flag will be ignored.''
- * -- ANSI X3J11
- */
- if (!sign)
- sign = ' ';
- goto rflag;
- case '#':
- flags |= ALT;
- goto rflag;
- case '*':
- /*-
- * ``A negative field width argument is taken as a
- * - flag followed by a positive field width.''
- * -- ANSI X3J11
- * They don't exclude field widths read from args.
- */
- GETASTER (width);
- if (width >= 0)
- goto rflag;
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '\'':
- flags |= GROUPING;
-#if defined(__ANDROID__)
- thousands_sep = ',';
-#else
- thousands_sep = (wchar_t) *(localeconv()->thousands_sep);
- grouping = localeconv()->grouping;
-#endif
-
- /*
- * Grouping should not begin with 0, but it nevertheless
- * does (see bug 281072) and makes the formatting code
- * behave badly, so we fix it up.
- */
-
- if (grouping != NULL && *grouping == '\0') {
- static char g[] = { CHAR_MAX, '\0' };
- grouping = g;
- }
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- GETASTER (prec);
- goto rflag;
- }
- prec = 0;
- while (is_digit(ch)) {
- prec = 10 * prec + to_digit(ch);
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- /*-
- * ``Note that 0 is taken as a flag, not as the
- * beginning of a field width.''
- * -- ANSI X3J11
- */
- flags |= ZEROPAD;
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- if (ch == '$') {
- nextarg = n;
- FIND_ARGUMENTS();
- goto rflag;
- }
- width = n;
- goto reswitch;
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'I':
- /* could be I64 - long long int is 64bit */
- if (fmt[0] == '6' && fmt[1] == '4') {
- fmt += 2;
- flags |= LLONGINT;
- goto rflag;
- }
- /* could be I32 - normal int is 32bit */
- if (fmt[0] == '3' && fmt[1] == '2') {
- fmt += 2;
- /* flags |= normal integer - it is 32bit for all our targets */
- goto rflag;
- }
- /*
- * I alone - use Microsoft's semantic as size_t modifier. We do
- * not support glibc's semantic to use alternative digits.
- */
- flags |= SIZET;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'L':
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'Z':
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
-#if defined(__ANDROID__)
- *(cp = buf) = (wchar_t)GETARG(wint_t);
-#else
- if (flags & LONGINT)
- *(cp = buf) = (wchar_t)GETARG(wint_t);
- else
- *(cp = buf) = (wchar_t)bsd_btowc(GETARG(int));
-#endif
- size = 1;
- sign = '\0';
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- if (flags & INTMAX_SIZE) {
- ujval = SJARG();
- if ((intmax_t)ujval < 0) {
- ujval = -ujval;
- sign = '-';
- }
- } else {
- ulval = SARG();
- if ((long)ulval < 0) {
- ulval = -ulval;
- sign = '-';
- }
- }
- base = 10;
- goto number;
-#ifndef NO_FLOATING_POINT
- case 'e':
- case 'E':
- expchar = ch;
- if (prec < 0) /* account for digit before decpt */
- prec = DEFPREC + 1;
- else
- prec++;
- goto fp_begin;
- case 'f':
- case 'F':
- expchar = '\0';
- goto fp_begin;
- case 'g':
- case 'G':
- expchar = ch - ('g' - 'e');
- if (prec == 0)
- prec = 1;
- fp_begin:
- if (prec < 0)
- prec = DEFPREC;
- if (convbuf != NULL)
- free(convbuf);
- if (flags & LLONGINT) {
- fparg.ldbl = GETARG(long double);
-#if defined NO_DTOA
- dtoaresult = NULL;
- /*
- * Below is to keep compiler happy
- */
- signflag = -1;
- expt = 0;
- dtoaend = NULL;
-#else
- dtoaresult =
- ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, &expt, &signflag,
- &dtoaend);
-#endif
- } else {
- fparg.dbl = GETARG(double);
-#if defined NO_DTOA
- dtoaresult = NULL;
- /*
- * Below is to keep compiler happy
- */
- signflag = -1;
- expt = 0;
- dtoaend = NULL;
-#else
- dtoaresult =
- dtoa(fparg.dbl, expchar ? 2 : 3, prec, &expt, &signflag,
- &dtoaend);
-#endif
- if (expt == 9999)
- expt = INT_MAX;
- }
- ndig = dtoaend - dtoaresult;
- cp = convbuf = BSDFmt_UTF8ToWChar(dtoaresult, -1);
- freedtoa(dtoaresult);
- if (signflag)
- sign = '-';
- if (expt == INT_MAX) { /* inf or nan */
- if (*cp == 'N') {
- cp = (ch >= 'a') ? L"nan" : L"NAN";
- sign = '\0';
- } else
- cp = (ch >= 'a') ? L"inf" : L"INF";
- size = 3;
- break;
- }
- flags |= FPT;
- if (ch == 'g' || ch == 'G') {
- if (expt > -4 && expt <= prec) {
- /* Make %[gG] smell like %[fF] */
- expchar = '\0';
- if (flags & ALT)
- prec -= expt;
- else
- prec = ndig - expt;
- if (prec < 0)
- prec = 0;
- } else {
- /*
- * Make %[gG] smell like %[eE], but
- * trim trailing zeroes if no # flag.
- */
- if (!(flags & ALT))
- prec = ndig;
- }
- }
- if (expchar) {
- expsize = exponent(expstr, expt - 1, expchar);
- size = expsize + prec;
- if (prec > 1 || flags & ALT)
- ++size;
- } else {
- /* space for digits before decimal point */
- if (expt > 0)
- size = expt;
- else /* "0" */
- size = 1;
- /* space for decimal pt and following digits */
- if (prec || flags & ALT)
- size += prec + 1;
- if (grouping && expt > 0) {
- /* space for thousands' grouping */
- nseps = nrepeats = 0;
- lead = expt;
- while (*grouping != CHAR_MAX) {
- if (lead <= *grouping)
- break;
- lead -= *grouping;
- if (*(grouping+1)) {
- nseps++;
- grouping++;
- } else
- nrepeats++;
- }
- size += nseps + nrepeats;
- } else
- lead = expt;
- }
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- /*
- * Assignment-like behavior is specified if the
- * value overflows or is otherwise unrepresentable.
- * C99 says to use `signed char' for %hhn conversions.
- */
- if (flags & LLONGINT)
- *GETARG(long long *) = ret;
- else if (flags & SIZET)
- *GETARG(size_t *) = (size_t)ret;
- else if (flags & PTRDIFFT)
- *GETARG(ptrdiff_t *) = ret;
- else if (flags & INTMAXT)
- *GETARG(intmax_t *) = ret;
- else if (flags & LONGINT)
- *GETARG(long *) = ret;
- else if (flags & SHORTINT)
- *GETARG(short *) = ret;
- else if (flags & CHARINT)
- *GETARG(signed char *) = ret;
- else
- *GETARG(int *) = ret;
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 8;
- goto nosign;
- case 'p':
- /*-
- * ``The argument shall be a pointer to void. The
- * value of the pointer is converted to a sequence
- * of printable characters, in an implementation-
- * defined manner.''
- * -- ANSI X3J11
- */
- ujval = (uintmax_t)(uintptr_t)GETARG(void *);
- base = 16;
- xdigs = xdigs_lower;
- flags = flags | INTMAXT;
- /*
- * PR 103201
- * VisualC sscanf doesn't grok '0x', so prefix zeroes.
- */
-// ox[1] = 'x';
- goto nosign;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (flags & LONGINT) {
- /* Argument is wchar_t * */
- if ((cp = GETARG(wchar_t *)) == NULL)
-#if defined(__ANDROID__) || TARGET_OS_IPHONE
- cp = (wchar_t *)L"(null)";
-#else
- cp = L"(null)";
-#endif
- } else {
- char *mbp;
- /* Argument is char * */
-
- if (convbuf!= NULL)
- free(convbuf);
- if ((mbp = GETARG(char *)) == NULL)
-#if defined(__ANDROID__) || TARGET_OS_IPHONE
- cp = (wchar_t *)L"(null)";
-#else
- cp = L"(null)";
-#endif
- else {
- convbuf = BSDFmt_UTF8ToWChar(mbp, prec);
- if (convbuf == NULL) {
- sbuf.error = TRUE;
- goto error;
- }
- cp = convbuf;
- }
- }
-
- if (prec >= 0) {
- /*
- * can't use wcslen; can only look for the
- * NUL in the first `prec' characters, and
- * wcslen() will go further.
- */
- wchar_t *p = (wchar_t *) wmemchr(cp, 0, (size_t)prec);
-
- if (p != NULL) {
- size = p - cp;
- if (size > prec)
- size = prec;
- } else
- size = prec;
- } else
- size = wcslen(cp);
- sign = '\0';
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 10;
- goto nosign;
- case 'X':
- xdigs = xdigs_upper;
- goto hex;
- case 'x':
- xdigs = xdigs_lower;
- hex:
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 16;
- /* leading 0x/X only if non-zero */
- if (flags & ALT &&
- (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
- ox[1] = ch;
-
- flags &= ~GROUPING;
- /* unsigned conversions */
- nosign: sign = '\0';
- /*-
- * ``... diouXx conversions ... if a precision is
- * specified, the 0 flag will be ignored.''
- * -- ANSI X3J11
- */
- number: if ((dprec = prec) >= 0)
- flags &= ~ZEROPAD;
-
- /*-
- * ``The result of converting a zero value with an
- * explicit precision of zero is no characters.''
- * -- ANSI X3J11
- *
- * ``The C Standard is clear enough as is. The call
- * printf("%#.0o", 0) should print 0.''
- * -- Defect Report #151
- */
- cp = buf + INT_CONV_BUF;
- if (flags & INTMAX_SIZE) {
- if (ujval != 0 || prec != 0 ||
- (flags & ALT && base == 8))
- cp = __ujtoa(ujval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- } else {
- if (ulval != 0 || prec != 0 ||
- (flags & ALT && base == 8))
- cp = __ultoa(ulval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- }
- size = buf + INT_CONV_BUF - cp;
- if (size > INT_CONV_BUF) /* should never happen */
- abort();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- /* pretend it was %c with argument ch */
- cp = buf;
- *cp = ch;
- size = 1;
- sign = '\0';
- break;
- }
-
- /*
- * All reasonable formats wind up here. At this point, `cp'
- * points to a string which (if not flags&LADJUST) should be
- * padded out to `width' places. If flags&ZEROPAD, it should
- * first be prefixed by any sign or other prefix; otherwise,
- * it should be blank padded before the prefix is emitted.
- * After any left-hand padding and prefixing, emit zeroes
- * required by a decimal [diouxX] precision, then print the
- * string proper, then emit zeroes required by any leftover
- * floating precision; finally, if LADJUST, pad with blanks.
- *
- * Compute actual size, so we know how much to pad.
- * size excludes decimal prec; realsz includes it.
- */
- realsz = dprec > size ? dprec : size;
- if (sign)
- realsz++;
- if (ox[1])
- realsz += 2;
-
- prsize = width > realsz ? width : realsz;
- if ((unsigned)ret + prsize > INT_MAX) {
- ret = EOF;
- goto error;
- }
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST|ZEROPAD)) == 0)
- PAD(width - realsz, blanks);
-
- /* prefix */
- if (sign)
- PRINT(&sign, 1);
-
- if (ox[1]) { /* ox[1] is either x, X, or \0 */
- ox[0] = '0';
- PRINT(ox, 2);
- }
-
- /* right-adjusting zero padding */
- if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
- PAD(width - realsz, zeroes);
-
- /* leading zeroes from decimal precision */
- PAD(dprec - size, zeroes);
-
- /* the string or number proper */
-#ifndef NO_FLOATING_POINT
- if ((flags & FPT) == 0) {
- PRINT(cp, size);
- } else { /* glue together f_p fragments */
- if (!expchar) { /* %[fF] or sufficiently short %[gG] */
- if (expt <= 0) {
- PRINT(zeroes, 1);
- if (prec || flags & ALT) {
- buf[0] = (wchar_t) *decimal_point;
- PRINT(buf, 1);
- }
- PAD(-expt, zeroes);
- /* already handled initial 0's */
- prec += expt;
- } else {
- PRINTANDPAD(cp, convbuf + ndig, lead, zeroes);
- cp += lead;
- if (grouping) {
- while (nseps>0 || nrepeats>0) {
- if (nrepeats > 0)
- nrepeats--;
- else {
- grouping--;
- nseps--;
- }
- PRINT(&thousands_sep,
- 1);
- PRINTANDPAD(cp,
- convbuf + ndig,
- *grouping, zeroes);
- cp += *grouping;
- }
- if (cp > convbuf + ndig)
- cp = convbuf + ndig;
- }
- if (prec || flags & ALT) {
- buf[0] = (wchar_t) *decimal_point;
- PRINT(buf, 1);
- }
- }
- PRINTANDPAD(cp, convbuf + ndig, prec, zeroes);
- } else { /* %[eE] or sufficiently long %[gG] */
- if (prec > 1 || flags & ALT) {
- buf[0] = *cp++;
- buf[1] = (wchar_t) *decimal_point;
- PRINT(buf, 2);
- PRINT(cp, ndig-1);
- PAD(prec - ndig, zeroes);
- } else /* XeYYY */
- PRINT(cp, 1);
- PRINT(expstr, expsize);
- }
- }
-#else
- PRINT(cp, size);
-#endif
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST)
- PAD(width - realsz, blanks);
-
- /* finally, adjust ret */
- ret += prsize;
-
- FLUSH(); /* copy out the I/O vectors */
- }
- done:
- FLUSH();
-
- /*
- * Always null terminate, unless buffer is size 0.
- */
-
- ASSERT(!sbuf.error && ret >= 0);
- if (sbuf.size <= 0) {
- ASSERT(!sbuf.alloc);
- } else {
- ASSERT(sbuf.index < sbuf.size);
- sbuf.buf[sbuf.index] = L'\0';
- }
-
- error:
-#ifndef _WIN32
- va_end(orgap);
-#endif
- if (convbuf != NULL)
- free(convbuf);
- if (sbuf.error)
- ret = EOF;
- if ((argtable != NULL) && (argtable != statargtable))
- free (argtable);
- return (ret);
- /* NOTREACHED */
-#undef FIND_ARGUMENTS
-}
-
-/*
- * Find all arguments when a positional parameter is encountered. Returns a
- * table, indexed by argument number, of pointers to each arguments. The
- * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
- * It will be replaces with a malloc-ed one if it overflows.
- */static void
- __find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
-{
- wchar_t *fmt; /* format string */
- wchar_t ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- wchar_t *cp; /* handy char pointer (short term usage) */
- int flags; /* flags as above */
- enum typeid *typetable; /* table of types */
- enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
- int tablesize; /* current size of type table */
- int tablemax; /* largest used index in table */
- int nextarg; /* 1-based argument index */
-
- /*
- * Add an argument type to the table, expanding if necessary.
- */
-#define ADDTYPE(type) \
- ((nextarg >= tablesize) ? \
- __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
- (nextarg > tablemax) ? tablemax = nextarg : 0, \
- typetable[nextarg++] = type)
-
-#define ADDSARG() \
- ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
- ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
- ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
- ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
- ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
-
-#define ADDUARG() \
- ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
- ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
- ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
- ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
- ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
-
- /*
- * Add * arguments to the type array.
- */
-#define ADDASTER() \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- nextarg = n2; \
- ADDTYPE (T_INT); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- ADDTYPE (T_INT); \
- }
- fmt = (wchar_t *)fmt0;
- typetable = stattypetable;
- tablesize = STATIC_ARG_TBL_SIZE;
- tablemax = 0; nextarg = 1;
- for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
- typetable[n] = T_UNUSED;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
-
- rflag: ch = *fmt++;
- reswitch: switch (ch) {
- case ' ':
- case '#':
- goto rflag;
- case '*':
- ADDASTER ();
- goto rflag;
- case '-':
- case '+':
- case '\'':
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- ADDASTER ();
- goto rflag;
- }
- while (is_digit(ch)) {
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- if (ch == '$') {
- nextarg = n;
- goto rflag;
- }
- goto reswitch;
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'I':
- /* could be I64 - long long int is 64bit */
- if (fmt[0] == '6' && fmt[1] == '4') {
- fmt += 2;
- flags |= LLONGINT;
- goto rflag;
- }
- /* could be I32 - normal int is 32bit */
- if (fmt[0] == '3' && fmt[1] == '2') {
- fmt += 2;
- /* flags |= normal integer - it is 32bit for all our targets */
- goto rflag;
- }
- /*
- * I alone - use Microsoft's semantic as size_t modifier. We do
- * not support glibc's semantic to use alternative digits.
- */
- flags |= SIZET;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'L':
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'Z':
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
- if (flags & LONGINT)
- ADDTYPE(T_WINT);
- else
- ADDTYPE(T_INT);
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- ADDSARG();
- break;
-#ifndef NO_FLOATING_POINT
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- if (flags & LLONGINT)
- ADDTYPE(T_LONG_DOUBLE);
- else
- ADDTYPE(T_DOUBLE);
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- if (flags & INTMAXT)
- ADDTYPE(TP_INTMAXT);
- else if (flags & PTRDIFFT)
- ADDTYPE(TP_PTRDIFFT);
- else if (flags & SIZET)
- ADDTYPE(TP_SIZET);
- else if (flags & LLONGINT)
- ADDTYPE(TP_LLONG);
- else if (flags & LONGINT)
- ADDTYPE(TP_LONG);
- else if (flags & SHORTINT)
- ADDTYPE(TP_SHORT);
- else if (flags & CHARINT)
- ADDTYPE(TP_SCHAR);
- else
- ADDTYPE(TP_INT);
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- ADDUARG();
- break;
- case 'p':
- ADDTYPE(TP_VOID);
- break;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (flags & LONGINT)
- ADDTYPE(TP_WCHAR);
- else
- ADDTYPE(TP_CHAR);
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- case 'X':
- case 'x':
- ADDUARG();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- break;
- }
- }
- done:
- /*
- * Build the argument table.
- */
- if (tablemax >= STATIC_ARG_TBL_SIZE) {
- *argtable = (union arg *)
- malloc (sizeof (union arg) * (tablemax + 1));
- }
-
- (*argtable) [0].intarg = 0;
- for (n = 1; n <= tablemax; n++) {
- switch (typetable [n]) {
- case T_UNUSED: /* whoops! */
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case TP_SCHAR:
- (*argtable) [n].pschararg = va_arg (ap, signed char *);
- break;
- case TP_SHORT:
- (*argtable) [n].pshortarg = va_arg (ap, short *);
- break;
- case T_INT:
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case T_U_INT:
- (*argtable) [n].uintarg = va_arg (ap, unsigned int);
- break;
- case TP_INT:
- (*argtable) [n].pintarg = va_arg (ap, int *);
- break;
- case T_LONG:
- (*argtable) [n].longarg = va_arg (ap, long);
- break;
- case T_U_LONG:
- (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
- break;
- case TP_LONG:
- (*argtable) [n].plongarg = va_arg (ap, long *);
- break;
- case T_LLONG:
- (*argtable) [n].longlongarg = va_arg (ap, long long);
- break;
- case T_U_LLONG:
- (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
- break;
- case TP_LLONG:
- (*argtable) [n].plonglongarg = va_arg (ap, long long *);
- break;
- case T_PTRDIFFT:
- (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
- break;
- case TP_PTRDIFFT:
- (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
- break;
- case T_SIZET:
- (*argtable) [n].sizearg = va_arg (ap, size_t);
- break;
- case TP_SIZET:
- (*argtable) [n].psizearg = va_arg (ap, size_t *);
- break;
- case T_INTMAXT:
- (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
- break;
- case T_UINTMAXT:
- (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
- break;
- case TP_INTMAXT:
- (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
- break;
-#ifndef NO_FLOATING_POINT
- case T_DOUBLE:
- (*argtable) [n].doublearg = va_arg (ap, double);
- break;
- case T_LONG_DOUBLE:
- (*argtable) [n].longdoublearg = va_arg (ap, long double);
- break;
-#endif
- case TP_CHAR:
- (*argtable) [n].pchararg = va_arg (ap, char *);
- break;
- case TP_VOID:
- (*argtable) [n].pvoidarg = va_arg (ap, void *);
- break;
- case T_WINT:
- (*argtable) [n].wintarg = va_arg (ap, wint_t);
- break;
- case TP_WCHAR:
- (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
- break;
- }
- }
-
- if ((typetable != NULL) && (typetable != stattypetable))
- free (typetable);
-}
-
-/*
- * Increase the size of the type table.
- */
-static void
-__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
-{
- enum typeid *const oldtable = *typetable;
- const int oldsize = *tablesize;
- enum typeid *newtable;
- int n, newsize = oldsize * 2;
-
- if (newsize < nextarg + 1)
- newsize = nextarg + 1;
- if (oldsize == STATIC_ARG_TBL_SIZE) {
- if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
- abort(); /* XXX handle better */
- memmove(newtable, oldtable, oldsize * sizeof(enum typeid));
- } else {
- newtable = realloc(oldtable, newsize * sizeof(enum typeid));
- if (newtable == NULL)
- abort(); /* XXX handle better */
- }
- for (n = oldsize; n < newsize; n++)
- newtable[n] = T_UNUSED;
-
- *typetable = newtable;
- *tablesize = newsize;
-}
-
-
-#ifndef NO_FLOATING_POINT
-
-static int
-exponent(wchar_t *p0, int exp, wchar_t fmtch)
-{
- wchar_t *p, *t;
- wchar_t expbuf[MAXEXPDIG];
-
- p = p0;
- *p++ = fmtch;
- if (exp < 0) {
- exp = -exp;
- *p++ = '-';
- }
- else
- *p++ = '+';
- t = expbuf + MAXEXPDIG;
-
- if (exp < 10) {
- *p++ = '0';
- }
-
- if (exp < 100) {
- *p++ = '0';
- }
-
- if (exp > 9) {
- do {
- *--t = to_char(exp % 10);
- } while ((exp /= 10) > 9);
- *--t = to_char(exp);
- for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
- } else {
- *p++ = to_char(exp);
- }
-
- return (p - p0);
-}
-
-#endif /* !NO_FLOATING_POINT */
-
-#endif /* !STR_NO_WIN32_LIBS|*BSD */
+++ /dev/null
-/* **********************************************************
- * Copyright 2008 VMware, Inc. All rights reserved.
- * **********************************************************/
-/*
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
- Conversions between UTF32, UTF-16, and UTF-8. Source code file.
- Author: Mark E. Davis, 1994.
- Rev History: Rick McGowan, fixes & updates May 2001.
- Sept 2001: fixed const & error conditions per
- mods suggested by S. Parent & A. Lillich.
- June 2002: Tim Dodd added detection and handling of incomplete
- source sequences, enhanced error detection, added casts
- to eliminate compiler warnings.
- July 2003: slight mods to back out aggressive FFFE detection.
- Jan 2004: updated switches in from-UTF8 conversions.
- Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
-
- See the header file "ConvertUTF.h" for complete documentation.
-
------------------------------------------------------------------------- */
-
-
-#include "convertutf.h"
-#ifdef CVTUTF_DEBUG
-#include <stdio.h>
-#endif
-
-static const int halfShift = 10; /* used for shifting by 10 bits */
-
-static const UTF32 halfBase = 0x0010000UL;
-static const UTF32 halfMask = 0x3FFUL;
-
-#define UNI_SUR_HIGH_START (UTF32)0xD800
-#define UNI_SUR_HIGH_END (UTF32)0xDBFF
-#define UNI_SUR_LOW_START (UTF32)0xDC00
-#define UNI_SUR_LOW_END (UTF32)0xDFFF
-#define false 0
-#define true 1
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- if (target >= targetEnd) {
- result = targetExhausted; break;
- }
- ch = *source++;
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_LEGAL_UTF32) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- --source; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF32* target = *targetStart;
- UTF32 ch, ch2;
- while (source < sourceEnd) {
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- if (target >= targetEnd) {
- source = oldSource; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- *target++ = ch;
- }
- *sourceStart = source;
- *targetStart = target;
-#ifdef CVTUTF_DEBUG
-if (result == sourceIllegal) {
- fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
- fflush(stderr);
-}
-#endif
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Index into the table below with the first byte of a UTF-8 sequence to
- * get the number of trailing bytes that are supposed to follow it.
- * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
- * left as-is for anyone who may want to do such conversion, which was
- * allowed in earlier algorithms.
- */
-static const char trailingBytesForUTF8[256] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-
-/*
- * Magic values subtracted from a buffer value during UTF8 conversion.
- * This table contains as many values as there might be trailing bytes
- * in a UTF-8 sequence.
- */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
- 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-
-/*
- * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
- * into the first byte, depending on how many bytes follow. There are
- * as many entries in this table as there are UTF-8 sequence types.
- * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
- * for *legal* UTF-8 will be 4 or fewer bytes total.
- */
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-/* --------------------------------------------------------------------- */
-
-/* The interface converts a whole buffer to avoid function-call overhead.
- * Constants have been gathered. Loops & conditionals have been removed as
- * much as possible for efficiency, in favor of drop-through switches.
- * (See "Note A" at the bottom of the file for equivalent code.)
- * If your compiler supports it, the "isLegalUTF8" call can be turned
- * into an inline function.
- */
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- UTF32 ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /* Figure out how many bytes the result will require */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- source = oldSource; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Utility routine to tell whether a sequence of bytes is legal UTF-8.
- * This must be called with the length pre-determined by the first byte.
- * If not calling this from ConvertUTF8to*, then the length can be set by:
- * length = trailingBytesForUTF8[*source]+1;
- * and the sequence is illegal right away if there aren't that many bytes
- * available.
- * If presented with a length > 4, this returns false. The Unicode
- * definition of UTF-8 goes up to 4-byte sequences.
- */
-
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
- UTF8 a;
- const UTF8 *srcptr = source+length;
- switch (length) {
- default: return false;
- /* Everything else falls through when "true"... */
- case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 2: if ((a = (*--srcptr)) > 0xBF) return false;
-
- switch (*source) {
- /* no fall-through in this inner switch */
- case 0xE0: if (a < 0xA0) return false; break;
- case 0xED: if (a > 0x9F) return false; break;
- case 0xF0: if (a < 0x90) return false; break;
- case 0xF4: if (a > 0x8F) return false; break;
- default: if (a < 0x80) return false;
- }
-
- case 1: if (*source >= 0x80 && *source < 0xC2) return false;
- }
- if (*source > 0xF4) return false;
- return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 sequence is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
- int length = trailingBytesForUTF8[*source]+1;
- if (source+length > sourceEnd) {
- return false;
- }
- return isLegalUTF8(source, length);
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (source + extraBytesToRead >= sourceEnd) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (! isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_UTF16) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- source -= (extraBytesToRead+1); /* return to the start */
- break; /* Bail out; shouldn't continue */
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- ch = *source++;
- if (flags == strictConversion ) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /*
- * Figure out how many bytes the result will require. Turn any
- * illegally large UTF32 things (> Plane 17) into replacement chars.
- */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- result = sourceIllegal;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- --source; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF32* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (source + extraBytesToRead >= sourceEnd) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (! isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6;
- case 4: ch += *source++; ch <<= 6;
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up the source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_LEGAL_UTF32) {
- /*
- * UTF-16 surrogate values are illegal in UTF-32, and anything
- * over Plane 17 (> 0x10FFFF) is illegal.
- */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = ch;
- }
- } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
- result = sourceIllegal;
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* ---------------------------------------------------------------------
-
- Note A.
- The fall-through switches in UTF-8 reading code save a
- temp variable, some decrements & conditionals. The switches
- are equivalent to the following loop:
- {
- int tmpBytesToRead = extraBytesToRead+1;
- do {
- ch += *source++;
- --tmpBytesToRead;
- if (tmpBytesToRead) ch <<= 6;
- } while (tmpBytesToRead > 0);
- }
- In UTF-8 writing code, the switches on "bytesToWrite" are
- similarly unrolled loops.
-
- --------------------------------------------------------------------- */
+++ /dev/null
-/* **********************************************************
- * Copyright 2008 VMware, Inc. All rights reserved.
- * **********************************************************/
-/*
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
- Conversions between UTF32, UTF-16, and UTF-8. Header file.
-
- Several funtions are included here, forming a complete set of
- conversions between the three formats. UTF-7 is not included
- here, but is handled in a separate source file.
-
- Each of these routines takes pointers to input buffers and output
- buffers. The input buffers are const.
-
- Each routine converts the text between *sourceStart and sourceEnd,
- putting the result into the buffer between *targetStart and
- targetEnd. Note: the end pointers are *after* the last item: e.g.
- *(sourceEnd - 1) is the last item.
-
- The return result indicates whether the conversion was successful,
- and if not, whether the problem was in the source or target buffers.
- (Only the first encountered problem is indicated.)
-
- After the conversion, *sourceStart and *targetStart are both
- updated to point to the end of last text successfully converted in
- the respective buffers.
-
- Input parameters:
- sourceStart - pointer to a pointer to the source buffer.
- The contents of this are modified on return so that
- it points at the next thing to be converted.
- targetStart - similarly, pointer to pointer to the target buffer.
- sourceEnd, targetEnd - respectively pointers to the ends of the
- two buffers, for overflow checking only.
-
- These conversion functions take a ConversionFlags argument. When this
- flag is set to strict, both irregular sequences and isolated surrogates
- will cause an error. When the flag is set to lenient, both irregular
- sequences and isolated surrogates are converted.
-
- Whether the flag is strict or lenient, all illegal sequences will cause
- an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
- or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
- must check for illegal sequences.
-
- When the flag is set to lenient, characters over 0x10FFFF are converted
- to the replacement character; otherwise (when the flag is set to strict)
- they constitute an error.
-
- Output parameters:
- The value "sourceIllegal" is returned from some routines if the input
- sequence is malformed. When "sourceIllegal" is returned, the source
- value will point to the illegal value that caused the problem. E.g.,
- in UTF-8 when a sequence is malformed, it points to the start of the
- malformed sequence.
-
- Author: Mark E. Davis, 1994.
- Rev History: Rick McGowan, fixes & updates May 2001.
- Fixes & updates, Sept 2001.
-
------------------------------------------------------------------------- */
-
-/* ---------------------------------------------------------------------
- The following 4 definitions are compiler-specific.
- The C standard does not guarantee that wchar_t has at least
- 16 bits, so wchar_t is no less portable than unsigned short!
- All should be unsigned values to avoid sign extension during
- bit mask & shift operations.
------------------------------------------------------------------------- */
-
-#include "vm_basic_types.h"
-
-typedef uint32 UTF32; /* at least 32 bits */
-typedef uint16 UTF16; /* at least 16 bits */
-typedef uint8 UTF8; /* typically 8 bits */
-typedef unsigned char Boolean; /* 0 or 1 */
-
-/* Some fundamental constants */
-#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
-#define UNI_MAX_BMP (UTF32)0x0000FFFF
-#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
-#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
-#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
-
-typedef enum {
- conversionOK, /* conversion successful */
- sourceExhausted, /* partial character in source, but hit end */
- targetExhausted, /* insuff. room in target for conversion */
- sourceIllegal /* source sequence is illegal/malformed */
-} ConversionResult;
-
-typedef enum {
- strictConversion = 0,
- lenientConversion
-} ConversionFlags;
-
-/* This is for C++ and does no harm in C */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* --------------------------------------------------------------------- */