/** * 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. */ RTDECL(int) RTStrFormatTypeDeregister(const char *pszType) { int32_t i; /* * Validate input. */ AssertPtr(pszType); /* * Locate the entry and remove it. */ rtstrFormatTypeWriteLock(); i = rtstrFormatTypeLookup(pszType, strlen(pszType)); if (i >= 0) { const uint32_t cTypes = g_cTypes; int32_t cToMove = cTypes - i - 1; if (cToMove > 0) memmove(&g_aTypes[i], &g_aTypes[i + 1], cToMove * sizeof(g_aTypes[i])); memset(&g_aTypes[cTypes - 1], 0, sizeof(g_aTypes[0])); ASMAtomicDecU32(&g_cTypes); } rtstrFormatTypeWriteUnlock(); Assert(i >= 0); return i >= 0 ? VINF_SUCCESS : 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. */ RTDECL(int) RTStrFormatTypeSetUser(const char *pszType, void *pvUser) { int32_t i; /* * Validate input. */ AssertPtr(pszType); /* * Locate the entry and update it. */ rtstrFormatTypeReadLock(); i = rtstrFormatTypeLookup(pszType, strlen(pszType)); if (i >= 0) ASMAtomicWritePtr(&g_aTypes[i].pvUser, pvUser); rtstrFormatTypeReadUnlock(); Assert(i >= 0); return i >= 0 ? VINF_SUCCESS : 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, va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize) { size_t cch; int32_t i; char const *pszTypeEnd; char const *pszType; char ch; void *pvValue = va_arg(*pArgs, void *); NOREF(chArgSize); /* * Parse out the type. */ pszType = *ppszFormat + 2; *ppszFormat = pszType; Assert(pszType[-1] == '['); Assert(pszType[-2] == 'R'); pszTypeEnd = pszType; while ((ch = *pszTypeEnd) != ']') { AssertReturn(ch != '\0', 0); AssertReturn(ch != '%', 0); AssertReturn(ch != '[', 0); pszTypeEnd++; } *ppszFormat = pszTypeEnd + 1; /* * Locate the entry and call the handler. */ rtstrFormatTypeReadLock(); i = rtstrFormatTypeLookup(pszType, pszTypeEnd - pszType); if (RT_LIKELY(i >= 0)) { #ifdef IN_RC PFNRTSTRFORMATTYPE pfnHandler = (PFNRTSTRFORMATTYPE)((intptr_t)&g_aTypes[0] + g_aTypes[i].offHandler); #else PFNRTSTRFORMATTYPE pfnHandler = g_aTypes[i].pfnHandler; #endif void *pvUser = ASMAtomicReadPtr(&g_aTypes[i].pvUser); rtstrFormatTypeReadUnlock(); cch = pfnHandler(pfnOutput, pvArgOutput, g_aTypes[i].szType, pvValue, cchWidth, cchPrecision, fFlags, pvUser); } else { rtstrFormatTypeReadUnlock(); cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<missing:%R[")); cch += pfnOutput(pvArgOutput, pszType, pszTypeEnd - pszType); cch += pfnOutput(pvArgOutput, RT_STR_TUPLE("]>")); } return cch; }