summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/common/err/errmsg-sorter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/err/errmsg-sorter.cpp')
-rw-r--r--src/VBox/Runtime/common/err/errmsg-sorter.cpp483
1 files changed, 483 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/err/errmsg-sorter.cpp b/src/VBox/Runtime/common/err/errmsg-sorter.cpp
new file mode 100644
index 00000000..a4c68865
--- /dev/null
+++ b/src/VBox/Runtime/common/err/errmsg-sorter.cpp
@@ -0,0 +1,483 @@
+/* $Id: errmsg-sorter.cpp $ */
+/** @file
+ * IPRT - Status code messages, sorter build program.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * 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 GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox 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.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+#include <VBox/err.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*
+ * Include the string table code.
+ */
+#define BLDPROG_STRTAB_MAX_STRLEN 512
+#define BLDPROG_STRTAB_WITH_COMPRESSION
+#define BLDPROG_STRTAB_PURE_ASCII
+#define BLDPROG_STRTAB_WITH_CAMEL_WORDS
+#include <iprt/bldprog-strtab-template.cpp.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** Used for raw-input and sorting. */
+typedef struct RTSTATUSMSGINT1
+{
+ /** Pointer to the short message string. */
+ const char *pszMsgShort;
+ /** Pointer to the full message string. */
+ const char *pszMsgFull;
+ /** Pointer to the define string. */
+ const char *pszDefine;
+ /** Status code number. */
+ int iCode;
+ /** Set if duplicate. */
+ bool fDuplicate;
+} RTSTATUSMSGINT1;
+typedef RTSTATUSMSGINT1 *PRTSTATUSMSGINT1;
+
+
+/** This is used when building the string table and printing it. */
+typedef struct RTSTATUSMSGINT2
+{
+ /** The short message string. */
+ BLDPROGSTRING MsgShort;
+ /** The full message string. */
+ BLDPROGSTRING MsgFull;
+ /** The define string. */
+ BLDPROGSTRING Define;
+ /** Pointer to the define string. */
+ const char *pszDefine;
+ /** Status code number. */
+ int iCode;
+ /** Index into the primary table (for multiple passes). */
+ unsigned idx1;
+} RTSTATUSMSGINT2;
+typedef RTSTATUSMSGINT2 *PRTSTATUSMSGINT2;
+
+
+/** This used to determin minimum field sizes. */
+typedef struct RTSTATUSMSGSTATS
+{
+ unsigned offMax;
+ unsigned cchMax;
+ unsigned cBitsOffset;
+ unsigned cBitsLength;
+} RTSTATUSMSGSTATS;
+typedef RTSTATUSMSGSTATS *PRTSTATUSMSGSTATS;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static const char *g_pszProgName = "errmsg-sorter";
+static RTSTATUSMSGINT1 g_aStatusMsgs[] =
+{
+#if !defined(IPRT_NO_ERROR_DATA) && !defined(DOXYGEN_RUNNING)
+# include "errmsgdata.h"
+#else
+ { "Success.", "Success.", "VINF_SUCCESS", 0, false },
+#endif
+};
+
+
+static RTEXITCODE error(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ fprintf(stderr, "%s: error: ", g_pszProgName);
+ vfprintf(stderr, pszFormat, va);
+ va_end(va);
+ return RTEXITCODE_FAILURE;
+}
+
+
+/** qsort callback. */
+static int CompareErrMsg(const void *pv1, const void *pv2) RT_NOTHROW_DEF
+{
+ PRTSTATUSMSGINT1 p1 = (PRTSTATUSMSGINT1)pv1;
+ PRTSTATUSMSGINT1 p2 = (PRTSTATUSMSGINT1)pv2;
+ int iDiff;
+ if (p1->iCode < p2->iCode)
+ iDiff = -1;
+ else if (p1->iCode > p2->iCode)
+ iDiff = 1;
+ else
+ iDiff = 0;
+ return iDiff;
+}
+
+
+/**
+ * Checks whether @a pszDefine is a deliberate duplicate define that should be
+ * omitted.
+ */
+static bool IgnoreDuplicateDefine(const char *pszDefine)
+{
+ size_t const cchDefine = strlen(pszDefine);
+
+ static const RTSTRTUPLE s_aTails[] =
+ {
+ { RT_STR_TUPLE("_FIRST") },
+ { RT_STR_TUPLE("_LAST") },
+ { RT_STR_TUPLE("_HIGEST") },
+ { RT_STR_TUPLE("_LOWEST") },
+ };
+ for (size_t i = 0; i < RT_ELEMENTS(s_aTails); i++)
+ if ( cchDefine > s_aTails[i].cch
+ && memcmp(&pszDefine[cchDefine - s_aTails[i].cch], s_aTails[i].psz, s_aTails[i].cch) == 0)
+ return true;
+
+ static const RTSTRTUPLE s_aDeliberateOrSilly[] =
+ {
+ { RT_STR_TUPLE("VERR_VRDP_TIMEOUT") },
+ { RT_STR_TUPLE("VINF_VRDP_SUCCESS") },
+ { RT_STR_TUPLE("VWRN_CONTINUE_RECOMPILE") },
+ { RT_STR_TUPLE("VWRN_PATM_CONTINUE_SEARCH") },
+ };
+ for (size_t i = 0; i < RT_ELEMENTS(s_aDeliberateOrSilly); i++)
+ if ( cchDefine == s_aDeliberateOrSilly[i].cch
+ && memcmp(pszDefine, s_aDeliberateOrSilly[i].psz, cchDefine) == 0)
+ return true;
+
+ return false;
+}
+
+
+DECLINLINE(void) GatherStringStats(PRTSTATUSMSGSTATS pStats, PBLDPROGSTRING pString)
+{
+ if (pStats->offMax < pString->offStrTab)
+ pStats->offMax = pString->offStrTab;
+ if (pStats->cchMax < pString->cchString)
+ pStats->cchMax = (unsigned)pString->cchString;
+}
+
+
+DECLINLINE(unsigned) CalcBitsForValue(size_t uValue)
+{
+ unsigned cBits = 1;
+ while (RT_BIT_64(cBits) < uValue && cBits < 64)
+ cBits++;
+ return cBits;
+}
+
+
+static void CalcBitsForStringStats(PRTSTATUSMSGSTATS pStats)
+{
+ pStats->cBitsOffset = CalcBitsForValue(pStats->offMax);
+ pStats->cBitsLength = CalcBitsForValue(pStats->cchMax);
+}
+
+
+int main(int argc, char **argv)
+{
+ /*
+ * Parse arguments.
+ */
+ enum { kMode_All, kMode_NoFullMsg, kMode_OnlyDefines } enmMode;
+ if (argc == 3 && strcmp(argv[1], "--all") == 0)
+ enmMode = kMode_All;
+ else if (argc == 3 && strcmp(argv[1], "--no-full-msg") == 0)
+ enmMode = kMode_NoFullMsg;
+ else if (argc == 3 && strcmp(argv[1], "--only-defines") == 0)
+ enmMode = kMode_OnlyDefines;
+ else
+ {
+ fprintf(stderr,
+ "syntax error!\n"
+ "Usage: %s <--all|--no-full-msg|--only-defines> <outfile>\n", argv[0]);
+ return RTEXITCODE_SYNTAX;
+ }
+ const char * const pszOutFile = argv[2];
+
+ /*
+ * Sort the table and mark duplicates.
+ */
+ qsort(g_aStatusMsgs, RT_ELEMENTS(g_aStatusMsgs), sizeof(g_aStatusMsgs[0]), CompareErrMsg);
+
+ int rcExit = RTEXITCODE_SUCCESS;
+ int iPrev = INT32_MAX;
+ for (size_t i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++)
+ {
+ /* Deal with duplicates, trying to eliminate unnecessary *_FIRST, *_LAST,
+ *_LOWEST, and *_HIGHEST entries as well as some deliberate duplicate entries.
+ This means we need to look forward and backwards here. */
+ PRTSTATUSMSGINT1 pMsg = &g_aStatusMsgs[i];
+ if (pMsg->iCode == iPrev && i != 0)
+ {
+ if (IgnoreDuplicateDefine(pMsg->pszDefine))
+ {
+ pMsg->fDuplicate = true;
+ continue;
+ }
+ PRTSTATUSMSGINT1 pPrev = &g_aStatusMsgs[i - 1];
+ rcExit = error("Duplicate value %d - %s and %s\n", iPrev, pMsg->pszDefine, pPrev->pszDefine);
+ }
+ else if (i + 1 < RT_ELEMENTS(g_aStatusMsgs))
+ {
+ PRTSTATUSMSGINT1 pNext = &g_aStatusMsgs[i];
+ if ( pMsg->iCode == pNext->iCode
+ && IgnoreDuplicateDefine(pMsg->pszDefine))
+ {
+ pMsg->fDuplicate = true;
+ continue;
+ }
+ }
+ iPrev = pMsg->iCode;
+ pMsg->fDuplicate = false;
+ }
+
+ /*
+ * Create a string table for it all.
+ */
+ BLDPROGSTRTAB StrTab;
+ if (!BldProgStrTab_Init(&StrTab, RT_ELEMENTS(g_aStatusMsgs) * 3))
+ return error("Out of memory!\n");
+
+ static RTSTATUSMSGINT2 s_aStatusMsgs2[RT_ELEMENTS(g_aStatusMsgs)];
+ unsigned cStatusMsgs = 0;
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++)
+ if (!g_aStatusMsgs[i].fDuplicate)
+ {
+ s_aStatusMsgs2[cStatusMsgs].idx1 = i;
+ s_aStatusMsgs2[cStatusMsgs].iCode = g_aStatusMsgs[i].iCode;
+ s_aStatusMsgs2[cStatusMsgs].pszDefine = g_aStatusMsgs[i].pszDefine;
+ BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[cStatusMsgs].Define, g_aStatusMsgs[i].pszDefine);
+ cStatusMsgs++;
+ }
+
+ if (enmMode != kMode_OnlyDefines)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[i].MsgShort, g_aStatusMsgs[s_aStatusMsgs2[i].idx1].pszMsgShort);
+
+ if (enmMode == kMode_All)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[i].MsgFull, g_aStatusMsgs[s_aStatusMsgs2[i].idx1].pszMsgFull);
+
+ if (!BldProgStrTab_CompileIt(&StrTab, true))
+ return error("BldProgStrTab_CompileIt failed!\n");
+
+ /*
+ * Prepare output file.
+ */
+ FILE *pOut = fopen(pszOutFile, "wt");
+ if (pOut)
+ {
+ /*
+ * .
+ */
+ RTSTATUSMSGSTATS Defines = {0, 0, 0, 0};
+ RTSTATUSMSGSTATS MsgShort = {0, 0, 0, 0};
+ RTSTATUSMSGSTATS MsgFull = {0, 0, 0, 0};
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ {
+ GatherStringStats(&Defines, &s_aStatusMsgs2[i].Define);
+ GatherStringStats(&MsgShort, &s_aStatusMsgs2[i].MsgShort);
+ GatherStringStats(&MsgFull, &s_aStatusMsgs2[i].MsgFull);
+ }
+ CalcBitsForStringStats(&Defines);
+ CalcBitsForStringStats(&MsgShort);
+ CalcBitsForStringStats(&MsgFull);
+ printf(" Defines: max offset %#x -> %u bits, max length %#x -> bits %u\n",
+ Defines.offMax, Defines.cBitsOffset, (unsigned)Defines.cchMax, Defines.cBitsLength);
+ if (enmMode != kMode_OnlyDefines)
+ printf("MsgShort: max offset %#x -> %u bits, max length %#x -> bits %u\n",
+ MsgShort.offMax, MsgShort.cBitsOffset, (unsigned)MsgShort.cchMax, MsgShort.cBitsLength);
+ if (enmMode == kMode_All)
+ printf(" MsgFull: max offset %#x -> %u bits, max length %#x -> bits %u\n",
+ MsgFull.offMax, MsgFull.cBitsOffset, (unsigned)MsgFull.cchMax, MsgFull.cBitsLength);
+
+ unsigned cBitsCodePos = CalcBitsForValue((size_t)s_aStatusMsgs2[cStatusMsgs - 1].iCode);
+ unsigned cBitsCodeNeg = CalcBitsForValue((size_t)-s_aStatusMsgs2[0].iCode);
+ unsigned cBitsCode = RT_MAX(cBitsCodePos, cBitsCodeNeg) + 1;
+ printf("Statuses: min %d, max %d -> %u bits\n",
+ s_aStatusMsgs2[0].iCode, s_aStatusMsgs2[cStatusMsgs - 1].iCode, cBitsCode);
+
+ /*
+ * Print the table.
+ */
+ fprintf(pOut,
+ "\n"
+ "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
+ "# pragma pack(1)\n"
+ "#endif\n"
+ "typedef struct RTMSGENTRYINT\n"
+ "{\n");
+ /* 16 + 16 + 8 */
+ bool fOptimalLayout = true;
+ if ( enmMode == kMode_OnlyDefines
+ && cBitsCode <= 16
+ && Defines.cBitsOffset <= 16
+ && Defines.cBitsLength <= 8)
+ fprintf(pOut,
+ " uint16_t offDefine; /* need %2u bits, max %#x */\n"
+ " uint8_t cchDefine; /* need %2u bits, max %#x */\n"
+ " int16_t iCode; /* need %2u bits */\n",
+ Defines.cBitsOffset, Defines.offMax, Defines.cBitsLength, Defines.cchMax, cBitsCode);
+ else if ( enmMode == kMode_NoFullMsg
+ && cBitsCode + Defines.cBitsOffset + Defines.cBitsLength + MsgShort.cBitsOffset + MsgShort.cBitsLength <= 64)
+ fprintf(pOut,
+ " uint64_t offDefine : %2u; /* max %#x */\n"
+ " uint64_t cchDefine : %2u; /* max %#x */\n"
+ " uint64_t offMsgShort : %2u; /* max %#x */\n"
+ " uint64_t cchMsgShort : %2u; /* max %#x */\n"
+ " int64_t iCode : %2u;\n",
+ Defines.cBitsOffset, Defines.offMax,
+ Defines.cBitsLength, Defines.cchMax,
+ MsgShort.cBitsOffset, MsgShort.offMax,
+ MsgShort.cBitsLength, MsgShort.cchMax,
+ cBitsCode);
+ else if ( enmMode == kMode_All
+ && Defines.cBitsOffset + Defines.cBitsLength
+ + MsgShort.cBitsOffset + MsgShort.cBitsLength
+ + MsgFull.cBitsOffset + MsgFull.cBitsLength
+ + cBitsCode <= 96
+ && cBitsCode + Defines.cBitsLength + MsgShort.cBitsLength <= 32)
+ fprintf(pOut,
+ " uint64_t offDefine : %2u; /* max %#x */\n"
+ " uint64_t offMsgShort : %2u; /* max %#x */\n"
+ " uint64_t offMsgFull : %2u; /* max %#x */\n"
+ " uint64_t cchMsgFull : %2u; /* max %#x */\n"
+ " int32_t iCode : %2u;\n"
+ " uint32_t cchDefine : %2u; /* max %#x */\n"
+ " uint32_t cchMsgShort : %2u; /* max %#x */\n",
+ Defines.cBitsOffset, Defines.offMax,
+ MsgShort.cBitsOffset, MsgShort.offMax,
+ MsgFull.cBitsOffset, MsgFull.offMax,
+ MsgFull.cBitsLength, MsgFull.cchMax,
+ cBitsCode,
+ Defines.cBitsLength, Defines.cchMax,
+ MsgShort.cBitsLength, MsgShort.cchMax);
+ else
+ {
+ fprintf(stderr, "%s: warning: Optimized structure layouts needs readjusting...\n", g_pszProgName);
+ fOptimalLayout = false;
+ fprintf(pOut,
+ " uint32_t offDefine : 23; /* need %u bits, max %#x */\n"
+ " uint32_t cchDefine : 9; /* need %u bits, max %#x */\n",
+ Defines.cBitsOffset, Defines.offMax, Defines.cBitsLength, Defines.cchMax);
+ if (enmMode != kMode_OnlyDefines)
+ fprintf(pOut,
+ " uint32_t offMsgShort : 23; /* need %u bits, max %#x */\n"
+ " uint32_t cchMsgShort : 9; /* need %u bits, max %#x */\n",
+ MsgShort.cBitsOffset, MsgShort.offMax, MsgShort.cBitsLength, MsgShort.offMax);
+ if (enmMode == kMode_All)
+ fprintf(pOut,
+ " uint32_t offMsgFull : 23; /* need %u bits, max %#x */\n"
+ " uint32_t cchMsgFull : 9; /* need %u bits, max %#x */\n",
+ MsgFull.cBitsOffset, MsgFull.offMax, MsgFull.cBitsLength, MsgFull.cchMax);
+ fprintf(pOut,
+ " int32_t iCode; /* need %u bits */\n", cBitsCode);
+ }
+ fprintf(pOut,
+ "} RTMSGENTRYINT;\n"
+ "typedef RTMSGENTRYINT *PCRTMSGENTRYINT;\n"
+ "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
+ "# pragma pack()\n"
+ "#endif\n"
+ "\n"
+ "static const RTMSGENTRYINT g_aStatusMsgs[ /*%lu*/ ] =\n"
+ "{\n"
+ ,
+ (unsigned long)cStatusMsgs);
+
+ if (enmMode == kMode_All && fOptimalLayout)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ fprintf(pOut, " { %#08x, %#08x, %#08x, %3u, %6d, %3u, %3u }, /* %s */\n",
+ s_aStatusMsgs2[i].Define.offStrTab,
+ s_aStatusMsgs2[i].MsgShort.offStrTab,
+ s_aStatusMsgs2[i].MsgFull.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].MsgFull.cchString,
+ s_aStatusMsgs2[i].iCode,
+ (unsigned)s_aStatusMsgs2[i].Define.cchString,
+ (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
+ s_aStatusMsgs2[i].pszDefine);
+ else if (enmMode == kMode_All)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ fprintf(pOut, " { %#08x, %3u, %#08x, %3u, %#08x, %3u, %8d }, /* %s */\n",
+ s_aStatusMsgs2[i].Define.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].Define.cchString,
+ s_aStatusMsgs2[i].MsgShort.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
+ s_aStatusMsgs2[i].MsgFull.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].MsgFull.cchString,
+ s_aStatusMsgs2[i].iCode,
+ s_aStatusMsgs2[i].pszDefine);
+ else if (enmMode == kMode_NoFullMsg)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ fprintf(pOut, " { %#08x, %3u, %#08x, %3u, %8d }, /* %s */\n",
+ s_aStatusMsgs2[i].Define.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].Define.cchString,
+ s_aStatusMsgs2[i].MsgShort.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
+ s_aStatusMsgs2[i].iCode,
+ s_aStatusMsgs2[i].pszDefine);
+ else if (enmMode == kMode_OnlyDefines)
+ for (size_t i = 0; i < cStatusMsgs; i++)
+ fprintf(pOut, " { %#08x, %3u, %8d }, /* %s */\n",
+ s_aStatusMsgs2[i].Define.offStrTab,
+ (unsigned)s_aStatusMsgs2[i].Define.cchString,
+ s_aStatusMsgs2[i].iCode,
+ s_aStatusMsgs2[i].pszDefine);
+ else
+ return error("Unsupported message selection (%d)!\n", enmMode);
+ fprintf(pOut,
+ "};\n"
+ "\n");
+
+ BldProgStrTab_WriteStringTable(&StrTab, pOut, "static ", "g_", "StatusMsgStrTab");
+
+ /*
+ * Close the output file and we're done.
+ */
+ fflush(pOut);
+ if (ferror(pOut))
+ rcExit = error("Error writing '%s'!\n", pszOutFile);
+ if (fclose(pOut) != 0)
+ rcExit = error("Failed to close '%s' after writing it!\n", pszOutFile);
+ }
+ else
+ rcExit = error("Failed to open '%s' for writing!\n", pszOutFile);
+ return rcExit;
+}
+