/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2013-2017 Nest Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include namespace chip { /** * Static buffer to store the formatted error string. */ static char sErrorStr[CHIP_CONFIG_ERROR_STR_SIZE]; /** * Linked-list of error formatter functions. */ static ErrorFormatter * sErrorFormatterList = nullptr; /** * This routine returns a human-readable NULL-terminated C string * describing the provided error. * * @param[in] err The error for format and describe. * @param[in] withSourceLocation Whether or not to include the source * location in the output string. Only used if CHIP_CONFIG_ERROR_SOURCE && * !CHIP_CONFIG_SHORT_ERROR_STR. Defaults to true. * * @return A pointer to a NULL-terminated C string describing the * provided error. */ DLL_EXPORT const char * ErrorStr(CHIP_ERROR err, bool withSourceLocation) { char * formattedError = sErrorStr; uint16_t formattedSpace = sizeof(sErrorStr); #if CHIP_CONFIG_ERROR_SOURCE && !CHIP_CONFIG_SHORT_ERROR_STR if (const char * const file = err.GetFile(); withSourceLocation && file != nullptr) { int n = snprintf(formattedError, formattedSpace, "%s:%u: ", file, err.GetLine()); if (n > formattedSpace) { n = formattedSpace; } formattedError += n; formattedSpace = static_cast(formattedSpace - n); } if (err == CHIP_NO_ERROR) { (void) snprintf(formattedError, formattedSpace, CHIP_NO_ERROR_STRING); return sErrorStr; } #else // CHIP_CONFIG_ERROR_SOURCE && !CHIP_CONFIG_SHORT_ERROR_STR if (err == CHIP_NO_ERROR) { return CHIP_NO_ERROR_STRING; } #endif // CHIP_CONFIG_ERROR_SOURCE && !CHIP_CONFIG_SHORT_ERROR_STR // Search the registered error formatter for one that will format the given // error code. for (const ErrorFormatter * errFormatter = sErrorFormatterList; errFormatter != nullptr; errFormatter = errFormatter->Next) { if (errFormatter->FormatError(formattedError, formattedSpace, err)) { return sErrorStr; } } // Use a default formatting if no formatter found. FormatError(formattedError, formattedSpace, nullptr, err, nullptr); return sErrorStr; } /** * Add a new error formatter function to the global list of error formatters. * * @param[in] errFormatter An ErrorFormatter structure containing a * pointer to the new error function. Note * that a pointer to the supplied ErrorFormatter * structure will be retained by the function. * Thus the memory for the structure must * remain reserved. */ DLL_EXPORT void RegisterErrorFormatter(ErrorFormatter * errFormatter) { // Do nothing if a formatter with the same format function is already in the list. for (ErrorFormatter * existingFormatter = sErrorFormatterList; existingFormatter != nullptr; existingFormatter = existingFormatter->Next) { if (existingFormatter->FormatError == errFormatter->FormatError) { return; } } // Add the formatter to the global list. errFormatter->Next = sErrorFormatterList; sErrorFormatterList = errFormatter; } /** * Remove an error formatter function from the global list of error formatters. * * @param[in] errFormatter An ErrorFormatter structure containing a * pointer to the new error function. */ DLL_EXPORT void DeregisterErrorFormatter(ErrorFormatter * errFormatter) { // Remove the formatter if present for (ErrorFormatter ** lfp = &sErrorFormatterList; *lfp != nullptr; lfp = &(*lfp)->Next) { // Remove the formatter from the global list, if found. if (*lfp == errFormatter) { *lfp = errFormatter->Next; } } } #if !CHIP_CONFIG_CUSTOM_ERROR_FORMATTER /** * Generates a human-readable NULL-terminated C string describing the provided error. * * @param[in] buf Buffer into which the error string will be placed. * @param[in] bufSize Size of the supplied buffer in bytes. * @param[in] subsys A short string describing the subsystem that originated * the error, or NULL if the origin of the error is * unknown/unavailable. This string should be 10 * characters or less. * @param[in] err The error to be formatted. * @param[in] desc A string describing the cause or meaning of the error, * or NULL if no such information is available. */ DLL_EXPORT void FormatError(char * buf, uint16_t bufSize, const char * subsys, CHIP_ERROR err, const char * desc) { #if CHIP_CONFIG_SHORT_ERROR_STR if (subsys == nullptr) { (void) snprintf(buf, bufSize, "Error " CHIP_CONFIG_SHORT_FORM_ERROR_VALUE_FORMAT, err.AsInteger()); } else { (void) snprintf(buf, bufSize, "Error %s:" CHIP_CONFIG_SHORT_FORM_ERROR_VALUE_FORMAT, subsys, err.AsInteger()); } #else // CHIP_CONFIG_SHORT_ERROR_STR const char * subsysSep = " "; const char * descSep = ": "; if (subsys == nullptr) { subsys = ""; subsysSep = ""; } if (desc == nullptr) { desc = ""; descSep = ""; } (void) snprintf(buf, bufSize, "%s%sError 0x%08" PRIX32 "%s%s", subsys, subsysSep, err.AsInteger(), descSep, desc); #endif // CHIP_CONFIG_SHORT_ERROR_STR } #endif // CHIP_CONFIG_CUSTOM_ERROR_FORMATTER } // namespace chip