From dc81979e78e1b8f42639aeb7aaec69f7ea49eb79 Mon Sep 17 00:00:00 2001 From: Oliver Kurth Date: Fri, 15 Sep 2017 11:23:41 -0700 Subject: [PATCH] Remove convertutf and bsd_printf The license for convertutf.c and convertutf.h does not explicitly permit, or prohibit, modification of the files, and restricts use to "products supporting the Unicode Standard". This is a problem for distribution with Debian, which complies to strict guidelines. See details at https://github.com/vmware/open-vm-tools/issues/148 and https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=823100 The code is not essential for open-vm-tools. It's needed by code in bsd_printf.c and related code, which in turn is needed by msgfmt.c and msgList.c. The latter code is not needed for open-vm-tools, and can therefore be eliminated from the open-vm-tools package. When HAS_BSD_PRINTF isn't set, Str_Snprintf() and Str_Vsnprintf will fall back to vsnprintf(), and Str_Asprintf()/Str_Vasprintf() will fall back to vasprintf(). Under Linux and FreeBSD these functions are properly implemented, and support %ls and %S. --- open-vm-tools/configure.ac | 9 - open-vm-tools/lib/file/fileLockPosix.c | 5 + open-vm-tools/lib/include/bsd_output.h | 58 - open-vm-tools/lib/include/bsdfmt.h | 216 -- open-vm-tools/lib/include/str.h | 5 + open-vm-tools/lib/misc/Makefile.am | 2 - open-vm-tools/lib/misc/msgList.c | 590 ---- open-vm-tools/lib/misc/msgfmt.c | 2852 ------------------ open-vm-tools/lib/string/Makefile.am | 8 - open-vm-tools/lib/string/bsd_output_int.h | 93 - open-vm-tools/lib/string/bsd_output_shared.c | 303 -- open-vm-tools/lib/string/bsd_vsnprintf.c | 1907 ------------ open-vm-tools/lib/string/bsd_vsnwprintf.c | 1737 ----------- open-vm-tools/lib/string/convertutf.c | 542 ---- open-vm-tools/lib/string/convertutf.h | 154 - 15 files changed, 10 insertions(+), 8471 deletions(-) delete mode 100644 open-vm-tools/lib/include/bsd_output.h delete mode 100644 open-vm-tools/lib/include/bsdfmt.h delete mode 100644 open-vm-tools/lib/misc/msgList.c delete mode 100644 open-vm-tools/lib/misc/msgfmt.c delete mode 100644 open-vm-tools/lib/string/bsd_output_int.h delete mode 100644 open-vm-tools/lib/string/bsd_output_shared.c delete mode 100644 open-vm-tools/lib/string/bsd_vsnprintf.c delete mode 100644 open-vm-tools/lib/string/bsd_vsnwprintf.c delete mode 100644 open-vm-tools/lib/string/convertutf.c delete mode 100644 open-vm-tools/lib/string/convertutf.h diff --git a/open-vm-tools/configure.ac b/open-vm-tools/configure.ac index bfd57dfb3..37291f0f5 100644 --- a/open-vm-tools/configure.ac +++ b/open-vm-tools/configure.ac @@ -1037,14 +1037,6 @@ if test "$enable_multimon" != "no"; then #include ]) fi -bsdPrintfWrappers=no -if test "$os" = "linux"; then - AC_CHECK_LIB([c], - [ecvt], - [bsdPrintfWrappers=yes], - []) -fi - ### ### Typdefs, structs, and compiler quarks. ### @@ -1321,7 +1313,6 @@ AM_CONDITIONAL(HAVE_GNU_LD, test "$with_gnu_ld" = "yes") 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") diff --git a/open-vm-tools/lib/file/fileLockPosix.c b/open-vm-tools/lib/file/fileLockPosix.c index e06bdc7dd..bbccca522 100644 --- a/open-vm-tools/lib/file/fileLockPosix.c +++ b/open-vm-tools/lib/file/fileLockPosix.c @@ -593,9 +593,14 @@ void 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 } diff --git a/open-vm-tools/lib/include/bsd_output.h b/open-vm-tools/lib/include/bsd_output.h deleted file mode 100644 index c23f5352c..000000000 --- a/open-vm-tools/lib/include/bsd_output.h +++ /dev/null @@ -1,58 +0,0 @@ -/********************************************************* - * 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_ diff --git a/open-vm-tools/lib/include/bsdfmt.h b/open-vm-tools/lib/include/bsdfmt.h deleted file mode 100644 index f021aac1f..000000000 --- a/open-vm-tools/lib/include/bsdfmt.h +++ /dev/null @@ -1,216 +0,0 @@ -/* ********************************************************** - * 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 -#include -#include -#include - -#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 -#include - -#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_ diff --git a/open-vm-tools/lib/include/str.h b/open-vm-tools/lib/include/str.h index 49c9c0062..2234a2611 100644 --- a/open-vm-tools/lib/include/str.h +++ b/open-vm-tools/lib/include/str.h @@ -60,25 +60,30 @@ extern "C" { #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 diff --git a/open-vm-tools/lib/misc/Makefile.am b/open-vm-tools/lib/misc/Makefile.am index d3d9c23c8..05f1e166e 100644 --- a/open-vm-tools/lib/misc/Makefile.am +++ b/open-vm-tools/lib/misc/Makefile.am @@ -37,8 +37,6 @@ libMisc_la_SOURCES += iovector.c 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 diff --git a/open-vm-tools/lib/misc/msgList.c b/open-vm-tools/lib/misc/msgList.c deleted file mode 100644 index 6e3ffa38c..000000000 --- a/open-vm-tools/lib/misc/msgList.c +++ /dev/null @@ -1,590 +0,0 @@ -/********************************************************* - * 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 -#include -#include - -#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; -} diff --git a/open-vm-tools/lib/misc/msgfmt.c b/open-vm-tools/lib/misc/msgfmt.c deleted file mode 100644 index 95e9e8dd8..000000000 --- a/open-vm-tools/lib/misc/msgfmt.c +++ /dev/null @@ -1,2852 +0,0 @@ -/* ********************************************************** - * 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 - #include - #include - #include - #include - #if defined(__FreeBSD__) - #include - #endif - #if !defined(_WIN32) && !defined(SOL9) && \ - (!defined(__FreeBSD__) || __FreeBSD_version >= 500029) - #include - #endif - #if !defined(__FreeBSD__) || __FreeBSD_version >= 400017 - #include - #endif - - #include "vmware.h" - #include "bsdfmt.h" - #include "err.h" -#endif - -#include "msgfmt.h" - -#ifdef HAS_BSD_PRINTF - #include - #include - #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>... --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 --hpreg */ - if (ubyte == '%') { - pos = in + 1; - sm = 1; - } - break; - - case 1: /* Found % --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>...!... --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 --hpreg */ - if (ubyte == '%') { - sm = 1; - } - break; - - case 1: /* Found % --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>...$... or %... --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>... --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 // } diff --git a/open-vm-tools/lib/string/Makefile.am b/open-vm-tools/lib/string/Makefile.am index 0677836c1..cc3674685 100644 --- a/open-vm-tools/lib/string/Makefile.am +++ b/open-vm-tools/lib/string/Makefile.am @@ -19,12 +19,4 @@ noinst_LTLIBRARIES = libString.la 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 - diff --git a/open-vm-tools/lib/string/bsd_output_int.h b/open-vm-tools/lib/string/bsd_output_int.h deleted file mode 100644 index b566e033d..000000000 --- a/open-vm-tools/lib/string/bsd_output_int.h +++ /dev/null @@ -1,93 +0,0 @@ -/* ********************************************************** - * 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_ diff --git a/open-vm-tools/lib/string/bsd_output_shared.c b/open-vm-tools/lib/string/bsd_output_shared.c deleted file mode 100644 index b56ac082e..000000000 --- a/open-vm-tools/lib/string/bsd_output_shared.c +++ /dev/null @@ -1,303 +0,0 @@ -/* ********************************************************** - * 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 - -#if !defined(STR_NO_WIN32_LIBS) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__) - -#include -#include -#ifndef _WIN32 -#include -#include -#endif -#include -#include -#include -#include -#ifdef __APPLE__ -#include -#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 */ diff --git a/open-vm-tools/lib/string/bsd_vsnprintf.c b/open-vm-tools/lib/string/bsd_vsnprintf.c deleted file mode 100644 index 5fa07af1f..000000000 --- a/open-vm-tools/lib/string/bsd_vsnprintf.c +++ /dev/null @@ -1,1907 +0,0 @@ -/* ********************************************************** - * 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 - -#include -#include -#include -#ifndef _WIN32 -#include -#include -#endif -#include -#include -#include -#include - -#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 */ diff --git a/open-vm-tools/lib/string/bsd_vsnwprintf.c b/open-vm-tools/lib/string/bsd_vsnwprintf.c deleted file mode 100644 index 7d68f39d8..000000000 --- a/open-vm-tools/lib/string/bsd_vsnwprintf.c +++ /dev/null @@ -1,1737 +0,0 @@ -/* ********************************************************** - * 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 -#include -#include - -#include -#include -#include -#include -#include - -#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 */ diff --git a/open-vm-tools/lib/string/convertutf.c b/open-vm-tools/lib/string/convertutf.c deleted file mode 100644 index 1c63b5456..000000000 --- a/open-vm-tools/lib/string/convertutf.c +++ /dev/null @@ -1,542 +0,0 @@ -/* ********************************************************** - * 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 -#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. - - --------------------------------------------------------------------- */ diff --git a/open-vm-tools/lib/string/convertutf.h b/open-vm-tools/lib/string/convertutf.h deleted file mode 100644 index 7fc00b8ba..000000000 --- a/open-vm-tools/lib/string/convertutf.h +++ /dev/null @@ -1,154 +0,0 @@ -/* ********************************************************** - * 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: , , - or 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 - -/* --------------------------------------------------------------------- */