VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/err/errmsg-sorter.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 19.2 KB
Line 
1/* $Id: errmsg-sorter.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Status code messages, sorter build program.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/err.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
44#include <VBox/err.h>
45
46#include <stdio.h>
47#include <stdlib.h>
48
49
50/*
51 * Include the string table code.
52 */
53#define BLDPROG_STRTAB_MAX_STRLEN 512
54#define BLDPROG_STRTAB_WITH_COMPRESSION
55#define BLDPROG_STRTAB_PURE_ASCII
56#define BLDPROG_STRTAB_WITH_CAMEL_WORDS
57#include <iprt/bldprog-strtab-template.cpp.h>
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/** Used for raw-input and sorting. */
64typedef struct RTSTATUSMSGINT1
65{
66 /** Pointer to the short message string. */
67 const char *pszMsgShort;
68 /** Pointer to the full message string. */
69 const char *pszMsgFull;
70 /** Pointer to the define string. */
71 const char *pszDefine;
72 /** Status code number. */
73 int iCode;
74 /** Set if duplicate. */
75 bool fDuplicate;
76} RTSTATUSMSGINT1;
77typedef RTSTATUSMSGINT1 *PRTSTATUSMSGINT1;
78
79
80/** This is used when building the string table and printing it. */
81typedef struct RTSTATUSMSGINT2
82{
83 /** The short message string. */
84 BLDPROGSTRING MsgShort;
85 /** The full message string. */
86 BLDPROGSTRING MsgFull;
87 /** The define string. */
88 BLDPROGSTRING Define;
89 /** Pointer to the define string. */
90 const char *pszDefine;
91 /** Status code number. */
92 int iCode;
93 /** Index into the primary table (for multiple passes). */
94 unsigned idx1;
95} RTSTATUSMSGINT2;
96typedef RTSTATUSMSGINT2 *PRTSTATUSMSGINT2;
97
98
99/** This used to determin minimum field sizes. */
100typedef struct RTSTATUSMSGSTATS
101{
102 unsigned offMax;
103 unsigned cchMax;
104 unsigned cBitsOffset;
105 unsigned cBitsLength;
106} RTSTATUSMSGSTATS;
107typedef RTSTATUSMSGSTATS *PRTSTATUSMSGSTATS;
108
109
110/*********************************************************************************************************************************
111* Global Variables *
112*********************************************************************************************************************************/
113static const char *g_pszProgName = "errmsg-sorter";
114static RTSTATUSMSGINT1 g_aStatusMsgs[] =
115{
116#if !defined(IPRT_NO_ERROR_DATA) && !defined(DOXYGEN_RUNNING)
117# include "errmsgdata.h"
118#else
119 { "Success.", "Success.", "VINF_SUCCESS", 0, false },
120#endif
121};
122
123
124static RTEXITCODE error(const char *pszFormat, ...)
125{
126 va_list va;
127 va_start(va, pszFormat);
128 fprintf(stderr, "%s: error: ", g_pszProgName);
129 vfprintf(stderr, pszFormat, va);
130 va_end(va);
131 return RTEXITCODE_FAILURE;
132}
133
134
135/** qsort callback. */
136static int CompareErrMsg(const void *pv1, const void *pv2) RT_NOTHROW_DEF
137{
138 PRTSTATUSMSGINT1 p1 = (PRTSTATUSMSGINT1)pv1;
139 PRTSTATUSMSGINT1 p2 = (PRTSTATUSMSGINT1)pv2;
140 int iDiff;
141 if (p1->iCode < p2->iCode)
142 iDiff = -1;
143 else if (p1->iCode > p2->iCode)
144 iDiff = 1;
145 else
146 iDiff = 0;
147 return iDiff;
148}
149
150
151/**
152 * Checks whether @a pszDefine is a deliberate duplicate define that should be
153 * omitted.
154 */
155static bool IgnoreDuplicateDefine(const char *pszDefine)
156{
157 size_t const cchDefine = strlen(pszDefine);
158
159 static const RTSTRTUPLE s_aTails[] =
160 {
161 { RT_STR_TUPLE("_FIRST") },
162 { RT_STR_TUPLE("_LAST") },
163 { RT_STR_TUPLE("_HIGEST") },
164 { RT_STR_TUPLE("_LOWEST") },
165 };
166 for (size_t i = 0; i < RT_ELEMENTS(s_aTails); i++)
167 if ( cchDefine > s_aTails[i].cch
168 && memcmp(&pszDefine[cchDefine - s_aTails[i].cch], s_aTails[i].psz, s_aTails[i].cch) == 0)
169 return true;
170
171 static const RTSTRTUPLE s_aDeliberateOrSilly[] =
172 {
173 { RT_STR_TUPLE("VERR_VRDP_TIMEOUT") },
174 { RT_STR_TUPLE("VINF_VRDP_SUCCESS") },
175 { RT_STR_TUPLE("VWRN_CONTINUE_RECOMPILE") },
176 { RT_STR_TUPLE("VWRN_PATM_CONTINUE_SEARCH") },
177 };
178 for (size_t i = 0; i < RT_ELEMENTS(s_aDeliberateOrSilly); i++)
179 if ( cchDefine == s_aDeliberateOrSilly[i].cch
180 && memcmp(pszDefine, s_aDeliberateOrSilly[i].psz, cchDefine) == 0)
181 return true;
182
183 return false;
184}
185
186
187DECLINLINE(void) GatherStringStats(PRTSTATUSMSGSTATS pStats, PBLDPROGSTRING pString)
188{
189 if (pStats->offMax < pString->offStrTab)
190 pStats->offMax = pString->offStrTab;
191 if (pStats->cchMax < pString->cchString)
192 pStats->cchMax = (unsigned)pString->cchString;
193}
194
195
196DECLINLINE(unsigned) CalcBitsForValue(size_t uValue)
197{
198 unsigned cBits = 1;
199 while (RT_BIT_64(cBits) < uValue && cBits < 64)
200 cBits++;
201 return cBits;
202}
203
204
205static void CalcBitsForStringStats(PRTSTATUSMSGSTATS pStats)
206{
207 pStats->cBitsOffset = CalcBitsForValue(pStats->offMax);
208 pStats->cBitsLength = CalcBitsForValue(pStats->cchMax);
209}
210
211
212int main(int argc, char **argv)
213{
214 /*
215 * Parse arguments.
216 */
217 enum { kMode_All, kMode_NoFullMsg, kMode_OnlyDefines } enmMode;
218 if (argc == 3 && strcmp(argv[1], "--all") == 0)
219 enmMode = kMode_All;
220 else if (argc == 3 && strcmp(argv[1], "--no-full-msg") == 0)
221 enmMode = kMode_NoFullMsg;
222 else if (argc == 3 && strcmp(argv[1], "--only-defines") == 0)
223 enmMode = kMode_OnlyDefines;
224 else
225 {
226 fprintf(stderr,
227 "syntax error!\n"
228 "Usage: %s <--all|--no-full-msg|--only-defines> <outfile>\n", argv[0]);
229 return RTEXITCODE_SYNTAX;
230 }
231 const char * const pszOutFile = argv[2];
232
233 /*
234 * Sort the table and mark duplicates.
235 */
236 qsort(g_aStatusMsgs, RT_ELEMENTS(g_aStatusMsgs), sizeof(g_aStatusMsgs[0]), CompareErrMsg);
237
238 int rcExit = RTEXITCODE_SUCCESS;
239 int iPrev = INT32_MAX;
240 for (size_t i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++)
241 {
242 /* Deal with duplicates, trying to eliminate unnecessary *_FIRST, *_LAST,
243 *_LOWEST, and *_HIGHEST entries as well as some deliberate duplicate entries.
244 This means we need to look forward and backwards here. */
245 PRTSTATUSMSGINT1 pMsg = &g_aStatusMsgs[i];
246 if (pMsg->iCode == iPrev && i != 0)
247 {
248 if (IgnoreDuplicateDefine(pMsg->pszDefine))
249 {
250 pMsg->fDuplicate = true;
251 continue;
252 }
253 PRTSTATUSMSGINT1 pPrev = &g_aStatusMsgs[i - 1];
254 rcExit = error("Duplicate value %d - %s and %s\n", iPrev, pMsg->pszDefine, pPrev->pszDefine);
255 }
256 else if (i + 1 < RT_ELEMENTS(g_aStatusMsgs))
257 {
258 PRTSTATUSMSGINT1 pNext = &g_aStatusMsgs[i];
259 if ( pMsg->iCode == pNext->iCode
260 && IgnoreDuplicateDefine(pMsg->pszDefine))
261 {
262 pMsg->fDuplicate = true;
263 continue;
264 }
265 }
266 iPrev = pMsg->iCode;
267 pMsg->fDuplicate = false;
268 }
269
270 /*
271 * Create a string table for it all.
272 */
273 BLDPROGSTRTAB StrTab;
274 if (!BldProgStrTab_Init(&StrTab, RT_ELEMENTS(g_aStatusMsgs) * 3))
275 return error("Out of memory!\n");
276
277 static RTSTATUSMSGINT2 s_aStatusMsgs2[RT_ELEMENTS(g_aStatusMsgs)];
278 unsigned cStatusMsgs = 0;
279 for (unsigned i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++)
280 if (!g_aStatusMsgs[i].fDuplicate)
281 {
282 s_aStatusMsgs2[cStatusMsgs].idx1 = i;
283 s_aStatusMsgs2[cStatusMsgs].iCode = g_aStatusMsgs[i].iCode;
284 s_aStatusMsgs2[cStatusMsgs].pszDefine = g_aStatusMsgs[i].pszDefine;
285 BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[cStatusMsgs].Define, g_aStatusMsgs[i].pszDefine);
286 cStatusMsgs++;
287 }
288
289 if (enmMode != kMode_OnlyDefines)
290 for (size_t i = 0; i < cStatusMsgs; i++)
291 BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[i].MsgShort, g_aStatusMsgs[s_aStatusMsgs2[i].idx1].pszMsgShort);
292
293 if (enmMode == kMode_All)
294 for (size_t i = 0; i < cStatusMsgs; i++)
295 BldProgStrTab_AddStringDup(&StrTab, &s_aStatusMsgs2[i].MsgFull, g_aStatusMsgs[s_aStatusMsgs2[i].idx1].pszMsgFull);
296
297 if (!BldProgStrTab_CompileIt(&StrTab, true))
298 return error("BldProgStrTab_CompileIt failed!\n");
299
300 /*
301 * Prepare output file.
302 */
303 FILE *pOut = fopen(pszOutFile, "wt");
304 if (pOut)
305 {
306 /*
307 * .
308 */
309 RTSTATUSMSGSTATS Defines = {0, 0, 0, 0};
310 RTSTATUSMSGSTATS MsgShort = {0, 0, 0, 0};
311 RTSTATUSMSGSTATS MsgFull = {0, 0, 0, 0};
312 for (size_t i = 0; i < cStatusMsgs; i++)
313 {
314 GatherStringStats(&Defines, &s_aStatusMsgs2[i].Define);
315 GatherStringStats(&MsgShort, &s_aStatusMsgs2[i].MsgShort);
316 GatherStringStats(&MsgFull, &s_aStatusMsgs2[i].MsgFull);
317 }
318 CalcBitsForStringStats(&Defines);
319 CalcBitsForStringStats(&MsgShort);
320 CalcBitsForStringStats(&MsgFull);
321 printf(" Defines: max offset %#x -> %u bits, max length %#x -> bits %u\n",
322 Defines.offMax, Defines.cBitsOffset, (unsigned)Defines.cchMax, Defines.cBitsLength);
323 if (enmMode != kMode_OnlyDefines)
324 printf("MsgShort: max offset %#x -> %u bits, max length %#x -> bits %u\n",
325 MsgShort.offMax, MsgShort.cBitsOffset, (unsigned)MsgShort.cchMax, MsgShort.cBitsLength);
326 if (enmMode == kMode_All)
327 printf(" MsgFull: max offset %#x -> %u bits, max length %#x -> bits %u\n",
328 MsgFull.offMax, MsgFull.cBitsOffset, (unsigned)MsgFull.cchMax, MsgFull.cBitsLength);
329
330 unsigned cBitsCodePos = CalcBitsForValue((size_t)s_aStatusMsgs2[cStatusMsgs - 1].iCode);
331 unsigned cBitsCodeNeg = CalcBitsForValue((size_t)-s_aStatusMsgs2[0].iCode);
332 unsigned cBitsCode = RT_MAX(cBitsCodePos, cBitsCodeNeg) + 1;
333 printf("Statuses: min %d, max %d -> %u bits\n",
334 s_aStatusMsgs2[0].iCode, s_aStatusMsgs2[cStatusMsgs - 1].iCode, cBitsCode);
335
336 /*
337 * Print the table.
338 */
339 fprintf(pOut,
340 "\n"
341 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
342 "# pragma pack(1)\n"
343 "#endif\n"
344 "typedef struct RTMSGENTRYINT\n"
345 "{\n");
346 /* 16 + 16 + 8 */
347 bool fOptimalLayout = true;
348 if ( enmMode == kMode_OnlyDefines
349 && cBitsCode <= 16
350 && Defines.cBitsOffset <= 16
351 && Defines.cBitsLength <= 8)
352 fprintf(pOut,
353 " uint16_t offDefine; /* need %2u bits, max %#x */\n"
354 " uint8_t cchDefine; /* need %2u bits, max %#x */\n"
355 " int16_t iCode; /* need %2u bits */\n",
356 Defines.cBitsOffset, Defines.offMax, Defines.cBitsLength, Defines.cchMax, cBitsCode);
357 else if ( enmMode == kMode_NoFullMsg
358 && cBitsCode + Defines.cBitsOffset + Defines.cBitsLength + MsgShort.cBitsOffset + MsgShort.cBitsLength <= 64)
359 fprintf(pOut,
360 " uint64_t offDefine : %2u; /* max %#x */\n"
361 " uint64_t cchDefine : %2u; /* max %#x */\n"
362 " uint64_t offMsgShort : %2u; /* max %#x */\n"
363 " uint64_t cchMsgShort : %2u; /* max %#x */\n"
364 " int64_t iCode : %2u;\n",
365 Defines.cBitsOffset, Defines.offMax,
366 Defines.cBitsLength, Defines.cchMax,
367 MsgShort.cBitsOffset, MsgShort.offMax,
368 MsgShort.cBitsLength, MsgShort.cchMax,
369 cBitsCode);
370 else if ( enmMode == kMode_All
371 && Defines.cBitsOffset + Defines.cBitsLength
372 + MsgShort.cBitsOffset + MsgShort.cBitsLength
373 + MsgFull.cBitsOffset + MsgFull.cBitsLength
374 + cBitsCode <= 96
375 && cBitsCode + Defines.cBitsLength + MsgShort.cBitsLength <= 32)
376 fprintf(pOut,
377 " uint64_t offDefine : %2u; /* max %#x */\n"
378 " uint64_t offMsgShort : %2u; /* max %#x */\n"
379 " uint64_t offMsgFull : %2u; /* max %#x */\n"
380 " uint64_t cchMsgFull : %2u; /* max %#x */\n"
381 " int32_t iCode : %2u;\n"
382 " uint32_t cchDefine : %2u; /* max %#x */\n"
383 " uint32_t cchMsgShort : %2u; /* max %#x */\n",
384 Defines.cBitsOffset, Defines.offMax,
385 MsgShort.cBitsOffset, MsgShort.offMax,
386 MsgFull.cBitsOffset, MsgFull.offMax,
387 MsgFull.cBitsLength, MsgFull.cchMax,
388 cBitsCode,
389 Defines.cBitsLength, Defines.cchMax,
390 MsgShort.cBitsLength, MsgShort.cchMax);
391 else
392 {
393 fprintf(stderr, "%s: warning: Optimized structure layouts needs readjusting...\n", g_pszProgName);
394 fOptimalLayout = false;
395 fprintf(pOut,
396 " uint32_t offDefine : 23; /* need %u bits, max %#x */\n"
397 " uint32_t cchDefine : 9; /* need %u bits, max %#x */\n",
398 Defines.cBitsOffset, Defines.offMax, Defines.cBitsLength, Defines.cchMax);
399 if (enmMode != kMode_OnlyDefines)
400 fprintf(pOut,
401 " uint32_t offMsgShort : 23; /* need %u bits, max %#x */\n"
402 " uint32_t cchMsgShort : 9; /* need %u bits, max %#x */\n",
403 MsgShort.cBitsOffset, MsgShort.offMax, MsgShort.cBitsLength, MsgShort.offMax);
404 if (enmMode == kMode_All)
405 fprintf(pOut,
406 " uint32_t offMsgFull : 23; /* need %u bits, max %#x */\n"
407 " uint32_t cchMsgFull : 9; /* need %u bits, max %#x */\n",
408 MsgFull.cBitsOffset, MsgFull.offMax, MsgFull.cBitsLength, MsgFull.cchMax);
409 fprintf(pOut,
410 " int32_t iCode; /* need %u bits */\n", cBitsCode);
411 }
412 fprintf(pOut,
413 "} RTMSGENTRYINT;\n"
414 "typedef RTMSGENTRYINT *PCRTMSGENTRYINT;\n"
415 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
416 "# pragma pack()\n"
417 "#endif\n"
418 "\n"
419 "static const RTMSGENTRYINT g_aStatusMsgs[ /*%lu*/ ] =\n"
420 "{\n"
421 ,
422 (unsigned long)cStatusMsgs);
423
424 if (enmMode == kMode_All && fOptimalLayout)
425 for (size_t i = 0; i < cStatusMsgs; i++)
426 fprintf(pOut, " { %#08x, %#08x, %#08x, %3u, %6d, %3u, %3u }, /* %s */\n",
427 s_aStatusMsgs2[i].Define.offStrTab,
428 s_aStatusMsgs2[i].MsgShort.offStrTab,
429 s_aStatusMsgs2[i].MsgFull.offStrTab,
430 (unsigned)s_aStatusMsgs2[i].MsgFull.cchString,
431 s_aStatusMsgs2[i].iCode,
432 (unsigned)s_aStatusMsgs2[i].Define.cchString,
433 (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
434 s_aStatusMsgs2[i].pszDefine);
435 else if (enmMode == kMode_All)
436 for (size_t i = 0; i < cStatusMsgs; i++)
437 fprintf(pOut, " { %#08x, %3u, %#08x, %3u, %#08x, %3u, %8d }, /* %s */\n",
438 s_aStatusMsgs2[i].Define.offStrTab,
439 (unsigned)s_aStatusMsgs2[i].Define.cchString,
440 s_aStatusMsgs2[i].MsgShort.offStrTab,
441 (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
442 s_aStatusMsgs2[i].MsgFull.offStrTab,
443 (unsigned)s_aStatusMsgs2[i].MsgFull.cchString,
444 s_aStatusMsgs2[i].iCode,
445 s_aStatusMsgs2[i].pszDefine);
446 else if (enmMode == kMode_NoFullMsg)
447 for (size_t i = 0; i < cStatusMsgs; i++)
448 fprintf(pOut, " { %#08x, %3u, %#08x, %3u, %8d }, /* %s */\n",
449 s_aStatusMsgs2[i].Define.offStrTab,
450 (unsigned)s_aStatusMsgs2[i].Define.cchString,
451 s_aStatusMsgs2[i].MsgShort.offStrTab,
452 (unsigned)s_aStatusMsgs2[i].MsgShort.cchString,
453 s_aStatusMsgs2[i].iCode,
454 s_aStatusMsgs2[i].pszDefine);
455 else if (enmMode == kMode_OnlyDefines)
456 for (size_t i = 0; i < cStatusMsgs; i++)
457 fprintf(pOut, " { %#08x, %3u, %8d }, /* %s */\n",
458 s_aStatusMsgs2[i].Define.offStrTab,
459 (unsigned)s_aStatusMsgs2[i].Define.cchString,
460 s_aStatusMsgs2[i].iCode,
461 s_aStatusMsgs2[i].pszDefine);
462 else
463 return error("Unsupported message selection (%d)!\n", enmMode);
464 fprintf(pOut,
465 "};\n"
466 "\n");
467
468 BldProgStrTab_WriteStringTable(&StrTab, pOut, "static ", "g_", "StatusMsgStrTab");
469
470 /*
471 * Close the output file and we're done.
472 */
473 fflush(pOut);
474 if (ferror(pOut))
475 rcExit = error("Error writing '%s'!\n", pszOutFile);
476 if (fclose(pOut) != 0)
477 rcExit = error("Failed to close '%s' after writing it!\n", pszOutFile);
478 }
479 else
480 rcExit = error("Failed to open '%s' for writing!\n", pszOutFile);
481 return rcExit;
482}
483
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use