Exemplo n.º 1
0
/**
 * Create a new thread.
 *
 * Same as RTThreadCreate except the name is given in the RTStrPrintfV form.
 *
 * @returns iprt status code.
 * @param   pThread     See RTThreadCreate.
 * @param   pfnThread   See RTThreadCreate.
 * @param   pvUser      See RTThreadCreate.
 * @param   cbStack     See RTThreadCreate.
 * @param   enmType     See RTThreadCreate.
 * @param   fFlags      See RTThreadCreate.
 * @param   pszNameFmt  Thread name format.
 * @param   va          Format arguments.
 */
RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
                            RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va)
{
    char szName[RTTHREAD_NAME_LEN * 2];
    RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
    return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
}
Exemplo n.º 2
0
/**
 * The function PassVA and PassVA2 calls.
 */
static DECLCALLBACK(int) PassVACallback(PUVM pUVM, unsigned u4K, unsigned u1G, const char *pszFormat, va_list *pva)
{
    NOREF(pUVM);
    if (u4K != _4K)
    {
        RTPrintf(TESTCASE ": u4K=%#x!\n", u4K);
        g_cErrors++;
    }
    if (u1G != _1G)
    {
        RTPrintf(TESTCASE ": u1G=%#x!\n", u1G);
        g_cErrors++;
    }

    if (strcmp(pszFormat, "hello %s"))
    {
        RTPrintf(TESTCASE ": pszFormat=%p:{%s}!\n", pszFormat, pszFormat);
        g_cErrors++;
    }

    char szBuf[1024];
    RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, *pva);
    if (strcmp(szBuf, "hello world"))
    {
        RTPrintf(TESTCASE ": RTStrPrintfV -> '%s'!\n", szBuf);
        g_cErrors++;
    }

    return VINF_SUCCESS;
}
Exemplo n.º 3
0
/**
 * RTStrPrintfv wrapper.
 *
 * @param   pszError            The error buffer.
 * @param   cbError             The size of the buffer.
 * @param   pszFormat           The error message format string.
 * @param   ...                 Format arguments.
 */
static void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...)
{
    va_list va;
    va_start(va, pszFormat);
    RTStrPrintfV(pszError, cbError, pszFormat, va);
    va_end(va);
}
Exemplo n.º 4
0
/**
 * Send a debugger event which takes the full source file location.
 *
 * @returns VBox status.
 * @param   pVM         Pointer to the VM.
 * @param   enmEvent    The event to send.
 * @param   pszFile     Source file.
 * @param   uLine       Line number in source file.
 * @param   pszFunction Function name.
 * @param   pszFormat   Message which accompanies the event.
 * @param   args        Message arguments.
 */
VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
{
    int rc = dbgfR3EventPrologue(pVM, enmEvent);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Format the message.
     */
    char   *pszMessage = NULL;
    char    szMessage[8192];
    if (pszFormat && *pszFormat)
    {
        pszMessage = &szMessage[0];
        RTStrPrintfV(szMessage, sizeof(szMessage), pszFormat, args);
    }

    /*
     * Send the event and process the reply communication.
     */
    pVM->dbgf.s.DbgEvent.enmType = enmEvent;
    pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
    pVM->dbgf.s.DbgEvent.u.Src.pszFile      = pszFile;
    pVM->dbgf.s.DbgEvent.u.Src.uLine        = uLine;
    pVM->dbgf.s.DbgEvent.u.Src.pszFunction  = pszFunction;
    pVM->dbgf.s.DbgEvent.u.Src.pszMessage   = pszMessage;
    return dbgfR3SendEvent(pVM);
}
Exemplo n.º 5
0
/**
 * Testings va_list passing in VMSetRuntimeError.
 */
static DECLCALLBACK(void) MyAtRuntimeError(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
{
    NOREF(pUVM);
    if (strcmp((const char *)pvUser, "user argument"))
    {
        RTPrintf(TESTCASE ": pvUser=%p:{%s}!\n", pvUser, (const char *)pvUser);
        g_cErrors++;
    }
    if (fFlags)
    {
        RTPrintf(TESTCASE ": fFlags=%#x!\n", fFlags);
        g_cErrors++;
    }
    if (strcmp(pszErrorId, "enum"))
    {
        RTPrintf(TESTCASE ": pszErrorId=%p:{%s}!\n", pszErrorId, pszErrorId);
        g_cErrors++;
    }
    if (strcmp(pszFormat, "some %s string"))
    {
        RTPrintf(TESTCASE ": pszFormat=%p:{%s}!\n", pszFormat, pszFormat);
        g_cErrors++;
    }

    char szBuf[1024];
    RTStrPrintfV(szBuf, sizeof(szBuf), pszFormat, va);
    if (strcmp(szBuf, "some error string"))
    {
        RTPrintf(TESTCASE ": RTStrPrintfV -> '%s'!\n", szBuf);
        g_cErrors++;
    }
}
Exemplo n.º 6
0
/**
 * RTStrPrintfv wrapper.
 *
 * @returns @a rc
 * @param   rc                  The status code to return.
 * @param   pszError            The error buffer.
 * @param   cbError             The size of the buffer.
 * @param   pszFormat           The error message format string.
 * @param   ...                 Format arguments.
 */
static int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...)
{
    va_list va;
    va_start(va, pszFormat);
    RTStrPrintfV(pszError, cbError, pszFormat, va);
    va_end(va);
    return rc;
}
Exemplo n.º 7
0
RTR3DECL(int) RTFileOpenV(PRTFILE pFile, uint64_t fOpen, const char *pszFilenameFmt, va_list va)
{
    char szFilename[RTPATH_MAX];
    size_t cchFilename = RTStrPrintfV(szFilename, sizeof(szFilename), pszFilenameFmt, va);
    if (cchFilename >= sizeof(szFilename) - 1)
        return VERR_FILENAME_TOO_LONG;
    return RTFileOpen(pFile, szFilename, fOpen);
}
Exemplo n.º 8
0
DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
{
    char szMsg[256];

    RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
    szMsg[sizeof(szMsg) - 1] = '\0';
    DbgPrint("%s", szMsg);

    NOREF(fInitial);
}
Exemplo n.º 9
0
// A helper for the various logging routines.
static void VLogF(const char *methodName, const char *fmt, va_list argptr)
{
	char buff[512];
#ifdef VBOX /* Enable the use of VBox formatting types. */
	RTStrPrintfV(buff, sizeof(buff), fmt, argptr);
#else
	// Use safer NS_ functions.
	PR_vsnprintf(buff, sizeof(buff), fmt, argptr);
#endif

	LogMessage(methodName, buff);
}
extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
{
# ifdef RT_OS_DARWIN
    ShutUpAppKit();
# endif /* RT_OS_DARWIN */

    /* We have to create QApplication anyway just to show the only one error-message.
     * This is a bit hackish as we don't have the argument vector handy. */
    int argc = 0;
    char *argv[2] = { NULL, NULL };
    QApplication a(argc, &argv[0]);

    /* Prepare the error-message: */
    QString strTitle = QApplication::tr("VirtualBox - Error In %1").arg(pszWhere);

    char szMsgBuf[1024];
    RTStrPrintfV(szMsgBuf, sizeof(szMsgBuf), pszMsgFmt, va);
    QString strText = QApplication::tr("<html><b>%1 (rc=%2)</b><br/><br/>").arg(szMsgBuf).arg(rc);
    strText.replace(QString("\n"), QString("<br>"));

    switch (enmWhat)
    {
        case kSupInitOp_Driver:
# ifdef RT_OS_LINUX
            strText += g_QStrHintLinuxNoDriver;
# else /* RT_OS_LINUX */
            strText += g_QStrHintOtherNoDriver;
# endif /* !RT_OS_LINUX */
            break;
# ifdef RT_OS_LINUX
        case kSupInitOp_IPRT:
        case kSupInitOp_Misc:
            if (rc == VERR_NO_MEMORY)
                strText += g_QStrHintLinuxNoMemory;
            else
# endif /* RT_OS_LINUX */
            if (rc == VERR_VM_DRIVER_VERSION_MISMATCH)
# ifdef RT_OS_LINUX
                strText += g_QStrHintLinuxWrongDriverVersion;
# else /* RT_OS_LINUX */
                strText += g_QStrHintOtherWrongDriverVersion;
# endif /* !RT_OS_LINUX */
            else
                strText += g_QStrHintReinstall;
            break;
        case kSupInitOp_Integrity:
        case kSupInitOp_RootCheck:
            strText += g_QStrHintReinstall;
            break;
        default:
            /* no hints here */
            break;
    }
Exemplo n.º 11
0
DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
{
    char szMsg[256];
    IPRT_LINUX_SAVE_EFL_AC();

    RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
    szMsg[sizeof(szMsg) - 1] = '\0';
    printk(KERN_EMERG "%s", szMsg);

    NOREF(fInitial);
    IPRT_LINUX_RESTORE_EFL_AC();
}
Exemplo n.º 12
0
/**
 * Alternative version of SUPR0Printf for Windows.
 *
 * @returns 0.
 * @param   pszFormat   The format string.
 */
SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
{
    va_list va;
    char    szMsg[512];

    va_start(va, pszFormat);
    size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
    szMsg[sizeof(szMsg) - 1] = '\0';
    va_end(va);

    RTLogWriteDebugger(szMsg, cch);
    return 0;
}
RTDECL(int)  RTMsgSetProgName(const char *pszFormat, ...)
{
    g_pszProgName = &g_szrtProcExePath[g_offrtProcName];

    va_list va;
    va_start(va, pszFormat);
    RTStrPrintfV(g_szProgName, sizeof(g_szProgName) - 1, pszFormat, va);
    va_end(va);

    g_pszProgName = g_szProgName;

    return VINF_SUCCESS;
}
Exemplo n.º 14
0
RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
{
    va_list     args;
    char        szMsg[512];

    va_start(args, pszFormat);
    RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
    va_end(args);

    szMsg[sizeof(szMsg) - 1] = '\0';
    cmn_err(CE_CONT, "%s", szMsg);
    return 0;
}
Exemplo n.º 15
0
RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
{
    va_list va;
    char    szMsg[512];

    va_start(va, pszFormat);
    RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
    va_end(va);
    szMsg[sizeof(szMsg) - 1] = '\0';

    printk("%s", szMsg);
    return 0;
}
Exemplo n.º 16
0
RTDECL(int) RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va)
{
    if (pErrInfo)
    {
        AssertPtr(pErrInfo);
        Assert((pErrInfo->fFlags & RTERRINFO_FLAGS_MAGIC_MASK) == RTERRINFO_FLAGS_MAGIC);

        RTStrPrintfV(pErrInfo->pszMsg, pErrInfo->cbMsg, pszFormat, va);
        pErrInfo->rc      = rc;
        pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
    }
    return rc;
}
Exemplo n.º 17
0
/**
 * Opens a file stream.
 *
 * @returns iprt status code.
 * @param   pszMode         The open mode. See fopen() standard.
 *                          Format: <a|r|w>[+][b|t]
 * @param   ppStream        Where to store the opened stream.
 * @param   pszFilenameFmt  Filename path format string.
 * @param   args            Arguments to the format string.
 */
RTR3DECL(int) RTStrmOpenFV(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, va_list args)
{
    int     rc;
    char    szFilename[RTPATH_MAX];
    size_t  cch = RTStrPrintfV(szFilename, sizeof(szFilename), pszFilenameFmt, args);
    if (cch < sizeof(szFilename))
        rc = RTStrmOpen(szFilename, pszMode, ppStream);
    else
    {
        AssertMsgFailed(("The filename is too long cch=%d\n", cch));
        rc = VERR_FILENAME_TOO_LONG;
    }
    return rc;
}
Exemplo n.º 18
0
SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
{
    va_list va;
    char szMsg[256];
    int cch;

    va_start(va, pszFormat);
    cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
    va_end(va);

    printf("%s", szMsg);

    return cch;
}
RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
{
    va_list     args;
    char        szMsg[512];

    /* cmn_err() acquires adaptive mutexes. Not preemption safe, see @bugref{6657}. */
    if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
        return 0;

    va_start(args, pszFormat);
    RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
    va_end(args);

    szMsg[sizeof(szMsg) - 1] = '\0';
    cmn_err(CE_CONT, "%s", szMsg);
    return 0;
}
Exemplo n.º 20
0
/*PRINTFLIKE2*/
void
ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
{
	size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
	va_list ap;
	size_t n;

	va_start(ap, format);
#ifndef VBOX
	n = vsnprintf(cd->cd_ptr, len, format, ap);
#else
	n = RTStrPrintfV(cd->cd_ptr, len, format, ap);
#endif
	va_end(ap);

	cd->cd_ptr += MIN(n, len);
	cd->cd_len += n;
}
Exemplo n.º 21
0
RTDECL(int) RTErrInfoAddV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va)
{
    if (pErrInfo)
    {
        AssertPtr(pErrInfo);
        Assert((pErrInfo->fFlags & RTERRINFO_FLAGS_MAGIC_MASK) == RTERRINFO_FLAGS_MAGIC);
        if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET)
        {
            char *pszOut = (char *)memchr(pErrInfo->pszMsg, '\0', pErrInfo->cbMsg - 2);
            if (pszOut)
                RTStrPrintfV(pszOut, &pErrInfo->pszMsg[pErrInfo->cbMsg] - pszOut, pszFormat, va);
        }
        else
        {
            while (*pszFormat == ' ')
                pszFormat++;
            return RTErrInfoSetV(pErrInfo, rc, pszFormat, va);
        }
    }
    return rc;
}
Exemplo n.º 22
0
/**
 * Constructs the path of a sysfs file from the format parameters passed,
 * prepending a prefix if the path is relative.
 *
 * @returns The number of characters returned, or -1 and errno set to ERANGE on
 *          failure.
 *
 * @param   pszPrefix  The prefix to prepend if the path is relative.  Must end
 *                     in '/'.
 * @param   pszBuf     Where to write the path.  Must be at least
 *                     sizeof(@a pszPrefix) characters long
 * @param   cchBuf     The size of the buffer pointed to by @a pszBuf.
 * @param   pszFormat  The name format, either absolute or relative to the
 *                     prefix specified by @a pszPrefix.
 * @param   va         The format args.
 */
static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf,
                                     const char *pszPrefix,
                                     const char *pszFormat, va_list va)
{
    size_t cchPrefix = strlen(pszPrefix);
    AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1);
    AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1);

    /** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to
     *        check for truncations. RTPath should provide some formatters and
     *        joiners which can take over this rather common task that is
     *        performed here. */
    size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va);
    if (*pszBuf != '/')
    {
        AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1);
        memmove(pszBuf + cchPrefix, pszBuf, cch + 1);
        memcpy(pszBuf, pszPrefix, cchPrefix);
        cch += cchPrefix;
    }
    return cch;
}
Exemplo n.º 23
0
/**
 * Worker for RTAssertMsg2V and RTAssertMsg2AddV
 *
 * @param   fInitial            True if it's RTAssertMsg2V, otherwise false.
 * @param   pszFormat           The message format string.
 * @param   va                  The format arguments.
 */
static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
{
    va_list vaCopy;
    size_t  cch;

    /*
     * The global first.
     */
    if (fInitial)
    {
        va_copy(vaCopy, va);
        cch = RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, vaCopy);
        ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
        va_end(vaCopy);
    }
    else
    {
        cch = ASMAtomicReadU32(&g_cchRTAssertMsg2);
        if (cch < sizeof(g_szRTAssertMsg2) - 4)
        {
            va_copy(vaCopy, va);
            cch += RTStrPrintfV(&g_szRTAssertMsg2[cch], sizeof(g_szRTAssertMsg2) - cch, pszFormat, vaCopy);
            ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
            va_end(vaCopy);
        }
    }

    /*
     * If not quiet, make some noise.
     */
    if (!RTAssertAreQuiet())
    {
        RTERRVARS SavedErrVars;
        RTErrVarsSave(&SavedErrVars);

#ifdef IN_RING0
# ifdef IN_GUEST_R0
        va_copy(vaCopy, va);
        RTLogBackdoorPrintfV(pszFormat, vaCopy);
        va_end(vaCopy);
# endif
        /** @todo fully integrate this with the logger... play safe a bit for now.  */
        rtR0AssertNativeMsg2V(fInitial, pszFormat, va);

#else  /* !IN_RING0 */
# if !defined(IN_RING3) && !defined(LOG_NO_COM)
#  if 0 /* Enable this iff you have a COM port and really want this debug info. */
        va_copy(vaCopy, va);
        RTLogComPrintfV(pszFormat, vaCopy);
        va_end(vaCopy);
#  endif
# endif

        PRTLOGGER pLog = RTLogRelGetDefaultInstance();
        if (pLog)
        {
            va_copy(vaCopy, va);
            RTLogRelPrintfV(pszFormat, vaCopy);
            va_end(vaCopy);
# ifndef IN_RC /* flushing is done automatically in RC */
            RTLogFlush(pLog);
# endif
        }

        pLog = RTLogDefaultInstance();
        if (pLog)
        {
            va_copy(vaCopy, va);
            RTLogPrintfV(pszFormat, vaCopy);
            va_end(vaCopy);
# ifndef IN_RC /* flushing is done automatically in RC */
            RTLogFlush(pLog);
#endif
        }

# ifdef IN_RING3
        /* print to stderr, helps user and gdb debugging. */
        char szMsg[sizeof(g_szRTAssertMsg2)];
        va_copy(vaCopy, va);
        RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
        va_end(vaCopy);
        fprintf(stderr, "%s", szMsg);
        fflush(stderr);
# endif
#endif /* !IN_RING0 */

        RTErrVarsRestore(&SavedErrVars);
    }
}
Exemplo n.º 24
0
/**
 * Special entrypoint used by the hardening code when something goes south.
 *
 * Display an error dialog to the user.
 *
 * @param   pszWhere    Indicates where the error occured.
 * @param   enmWhat     Indicates what init operation was going on at the time.
 * @param   rc          The VBox status code corresponding to the error.
 * @param   pszMsgFmt   The message format string.
 * @param   va          Format arguments.
 */
extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
{
# ifdef VBOX_WS_MAC
    /* Hide setuid root from AppKit: */
    HideSetUidRootFromAppKit();
# endif /* VBOX_WS_MAC */

    char szMsgBuf[_16K];

    /*
     * We have to create QApplication anyway just to show the only one error-message.
     * This is a bit hackish as we don't have the argument vector handy.
     */
    int argc = 0;
    char *argv[2] = { NULL, NULL };
    QApplication a(argc, &argv[0]);

    /*
     * The details starts off a properly formatted rc and where/what, we use
     * the szMsgBuf for this, thus this have to come before the actual message
     * formatting.
     */
    RTStrPrintf(szMsgBuf, sizeof(szMsgBuf),
                "<!--EOM-->"
                "where: %s\n"
                "what:  %d\n"
                "%Rra\n",
                pszWhere, enmWhat, rc);
    QString strDetails = szMsgBuf;

    /*
     * Format the error message. Take whatever comes after a double new line as
     * something better off in the details section.
     */
    RTStrPrintfV(szMsgBuf, sizeof(szMsgBuf), pszMsgFmt, va);

    char *pszDetails = strstr(szMsgBuf, "\n\n");
    if (pszDetails)
    {
        while (RT_C_IS_SPACE(*pszDetails))
            *pszDetails++ = '\0';
        if (*pszDetails)
        {
            strDetails += "\n";
            strDetails += pszDetails;
        }
        RTStrStripR(szMsgBuf);
    }

    QString strText = QApplication::tr("<html><b>%1 (rc=%2)</b><br/><br/>").arg(szMsgBuf).arg(rc);
    strText.replace(QString("\n"), QString("<br>"));

    /*
     * Append possibly helpful hints to the error message.
     */
    switch (enmWhat)
    {
        case kSupInitOp_Driver:
# ifdef RT_OS_LINUX
            strText += g_QStrHintLinuxNoDriver;
# else /* RT_OS_LINUX */
            strText += g_QStrHintOtherNoDriver;
# endif /* !RT_OS_LINUX */
            break;
# ifdef RT_OS_LINUX
        case kSupInitOp_IPRT:
        case kSupInitOp_Misc:
            if (rc == VERR_NO_MEMORY)
                strText += g_QStrHintLinuxNoMemory;
            else
# endif /* RT_OS_LINUX */
            if (rc == VERR_VM_DRIVER_VERSION_MISMATCH)
# ifdef RT_OS_LINUX
                strText += g_QStrHintLinuxWrongDriverVersion;
# else /* RT_OS_LINUX */
                strText += g_QStrHintOtherWrongDriverVersion;
# endif /* !RT_OS_LINUX */
            else
                strText += g_QStrHintReinstall;
            break;
        case kSupInitOp_Integrity:
        case kSupInitOp_RootCheck:
            strText += g_QStrHintReinstall;
            break;
        default:
            /* no hints here */
            break;
    }