strformattype.cpp revision 1939436fa43cbf7f5cdc05a3830ed624d5fe4a6a
/* $Id$ */
/** @file
* IPRT - IPRT String Formatter Extensions, Dynamic Types.
*/
/*
* Copyright (C) 2008-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_STRING
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#ifdef RT_STRICT
# define RTSTRFORMATTYPE_WITH_LOCKING
#endif
#ifdef RTSTRFORMATTYPE_WITH_LOCKING
# define RTSTRFORMATTYPE_LOCK_OFFSET 0x7fff0000
#endif
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Description of a registered formatting type.
*
* In GC we'll be using offsets instead of pointers just to try avoid having to
* do the bothersome relocating. This of course assumes that all the relevant
* code stays within the same mapping.
*/
typedef struct RTSTRDYNFMT
{
/** The length of the type. */
/** The type name. */
char szType[47];
/** The handler function.
* In GC the offset is relative to g_aTypes[0], so that &g_aTypes[0] + offHandler
* gives the actual address. */
#ifdef IN_RC
#else
#endif
/** Callback argument. */
void * volatile pvUser;
#if ARCH_BITS == 32
/** Size alignment padding. */
char abPadding[8];
#endif
} RTSTRDYNFMT;
typedef RTSTRDYNFMT *PRTSTRDYNFMT;
typedef RTSTRDYNFMT const *PCRTSTRDYNFMT;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The registered types, sorted for binary lookup.
* We use a static array here because it avoids RTMemAlloc dependencies+leaks. */
/** The number of registered types. */
#ifdef RTSTRFORMATTYPE_WITH_LOCKING
* Zero == unlocked, negative == write locked, positive == read locked.
*
* The user should do all the serialization and we'll smack his fingers in
* strict builds if he doesn't. */
static int32_t volatile g_i32Spinlock = 0;
#endif
/**
* Locks the stuff for updating.
*
* Mostly for check that the caller is doing his job.
*/
DECLINLINE(void) rtstrFormatTypeWriteLock(void)
{
#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
{
unsigned volatile i;
AssertFailed();
for (i = 0;; i++)
if ( !g_i32Spinlock
break;
}
#endif
}
/**
* Undoing rtstrFormatTypeWriteLock.
*/
DECLINLINE(void) rtstrFormatTypeWriteUnlock(void)
{
#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
Assert(g_i32Spinlock < 0);
#endif
}
/**
* Locks the stuff for reading.
*
* This is just cheap stuff to make sure the caller is doing the right thing.
*/
DECLINLINE(void) rtstrFormatTypeReadLock(void)
{
#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
{
unsigned volatile i;
AssertFailed();
for (i = 0;; i++)
if (ASMAtomicUoReadS32(&g_i32Spinlock) > 0)
break;
}
#endif
}
/**
* Undoing rtstrFormatTypeReadLock.
*/
DECLINLINE(void) rtstrFormatTypeReadUnlock(void)
{
#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
Assert(g_i32Spinlock > 0);
#endif
}
/**
* Compares a type string with a type entry, the string doesn't need to be terminated.
*
* @returns Same as memcmp.
* @param pszType The type string, doesn't need to be terminated.
* @param cchType The number of chars in @a pszType to compare.
* @param pType The type entry to compare with.
*/
{
if (!iDiff)
{
return 0;
}
return iDiff;
}
/**
* Looks up a type entry.
*
* @returns The type index, -1 on failure.
* @param pszType The type to look up. This doesn't have to be terminated.
* @param cchType The length of the type.
*/
{
/*
* Lookup the type - binary search.
*/
for (;;)
{
if (!iDiff)
return i;
break;
if (iDiff < 0)
iEnd = i - 1;
else
iStart = i + 1;
break;
}
return -1;
}
/**
* Register a format handler for a type.
*
* The format handler is used to handle '%R[type]' format types, where the argument
* in the vector is a pointer value (a bit restrictive, but keeps it simple).
*
* The caller must ensure that no other thread will be making use of any of
* the dynamic formatting type facilities simultaneously with this call.
*
* @returns IPRT status code.
* @retval VINF_SUCCESS on success.
* @retval VERR_ALREADY_EXISTS if the type has already been registered.
* @retval VERR_TOO_MANY_OPEN_FILES if all the type slots has been allocated already.
*
* @param pszType The type name.
* @param pfnHandler The handler address. See FNRTSTRFORMATTYPE for details.
* @param pvUser The user argument to pass to the handler. See RTStrFormatTypeSetUser
* for how to update this later.
*/
RTDECL(int) RTStrFormatTypeRegister(const char *pszType, PFNRTSTRFORMATTYPE pfnHandler, void *pvUser)
{
int rc;
/*
* Validate input.
*/
/*
* Try add it.
*/
/* check that there are empty slots. */
{
/* find where to insert it. */
uint32_t i = 0;
rc = VINF_SUCCESS;
while (i < cTypes)
{
if (!iDiff)
{
break;
}
if (iDiff < 0)
break;
i++;
}
if (RT_SUCCESS(rc))
{
/* make room. */
if (cToMove)
/* insert the new entry. */
#ifdef IN_RC
#else
#endif
rc = VINF_SUCCESS;
}
}
else
return rc;
}
/**
* Deregisters a format type.
*
* The caller must ensure that no other thread will be making use of any of
* the dynamic formatting type facilities simultaneously with this call.
*
* @returns IPRT status code.
* @retval VINF_SUCCESS on success.
* @retval VERR_FILE_NOT_FOUND if not found.
*
* @param pszType The type to deregister.
*/
{
int32_t i;
/*
* Validate input.
*/
/*
* Locate the entry and remove it.
*/
if (i >= 0)
{
if (cToMove > 0)
}
Assert(i >= 0);
return i >= 0
: VERR_FILE_NOT_FOUND; /** @todo fix status code */
}
/**
* Sets the user argument for a type.
*
* This can be used if a user argument needs relocating in GC.
*
* @returns IPRT status code.
* @retval VINF_SUCCESS on success.
* @retval VERR_FILE_NOT_FOUND if not found.
*
* @param pszType The type to update.
* @param pvUser The new user argument value.
*/
{
int32_t i;
/*
* Validate input.
*/
/*
* Locate the entry and update it.
*/
if (i >= 0)
Assert(i >= 0);
return i >= 0
: VERR_FILE_NOT_FOUND; /** @todo fix status code */
}
/**
* Formats a type using a registered callback handler.
*
* This will handle %R[type].
*
* @returns The number of bytes formatted.
* @param pfnOutput Pointer to output function.
* @param pvArgOutput Argument for the output function.
* @param ppszFormat Pointer to the format string pointer. Advance this till the char
* after the format specifier.
* @param pArgs Pointer to the argument list. Use this to fetch the arguments.
* @param cchWidth Format Width. -1 if not specified.
* @param cchPrecision Format Precision. -1 if not specified.
* @param fFlags Flags (RTSTR_NTFS_*).
* @param chArgSize The argument size specifier, 'l' or 'L'.
*/
DECLHIDDEN(size_t) rtstrFormatType(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat,
{
int32_t i;
char const *pszTypeEnd;
char const *pszType;
char ch;
/*
* Parse out the type.
*/
*ppszFormat = pszType;
{
pszTypeEnd++;
}
/*
* Locate the entry and call the handler.
*/
if (RT_LIKELY(i >= 0))
{
#ifdef IN_RC
PFNRTSTRFORMATTYPE pfnHandler = (PFNRTSTRFORMATTYPE)((intptr_t)&g_aTypes[0] + g_aTypes[i].offHandler);
#else
#endif
cch = pfnHandler(pfnOutput, pvArgOutput, g_aTypes[i].szType, pvValue, cchWidth, cchPrecision, fFlags, pvUser);
}
else
{
}
return cch;
}