1
/*********************************************************
2
* Copyright (C) 2009-2011 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Utilities to manipulate (stateless) lists of messages.
38
#define LOGLEVEL_MODULE main
39
#include "loglevel_user.h"
43
*-----------------------------------------------------------------------------
47
* Create a MsgList item from the input message. Does not handle arguments;
48
* the caller must handle those.
50
* Performs any needed sanity checks as well.
53
* A newly-allocated MsgList.
58
*-----------------------------------------------------------------------------
62
MsgId2MsgList(const char *idFmt) // IN message ID and English message
65
const char *idp, *strp;
67
/* All message strings must be prefixed by the message ID. */
68
ASSERT(Msg_HasMsgID(idFmt));
71
* Find the beginning of the ID (idp) and the string (strp).
72
* The string should have the correct MSG_MAGIC(...)... form.
75
idp = idFmt + MSG_MAGIC_LEN + 1;
76
strp = strchr(idp, ')') + 1;
78
m = Util_SafeMalloc(sizeof *m);
79
m->format = Util_SafeStrdup(strp);
86
static const char *prfx[] = {
87
"msg.", // bora/lib, VMX, ...
88
"vob.", // Vmkernel OBservation
89
"vpxa.", // VirtualCenter host agent
90
"vpxd.", // VirtualCenter server
91
"hostd.", // Host agent
92
// Additional prefixes go here, but do not add "button."
95
for (i = 0; i < ARRAYSIZE(prfx); i++) {
96
if (!Str_Strncasecmp(idp, prfx[i], strlen(prfx[i]))) {
100
if (i >= ARRAYSIZE(prfx)) {
101
Panic("%s error: Invalid msg prefix in <%s>\n", __FUNCTION__, idp);
105
m->id = Util_SafeStrndup(idp, strp - idp - 1 /* ')' character */);
112
*-----------------------------------------------------------------------------
114
* MsgList_AppendStr --
116
* Create a MsgList item from the input message. The input message MUST
117
* have no arguments. Do not pass in formatted messages; use MsgList_Append
118
* for that. This variant is only for MSGIDs that have no format arguments.
120
* If the incoming list pointer reference is NULL, operate in 'silent'
121
* mode: skip all work (except preconditions). Note that in silent +
122
* vmx86_debug mode, this code does all work and throws away the result,
123
* to make sure all messages are parseable.
126
* New item is attached to 'list' (and '*list' is updated).
129
* Callers are responsible to free the returned MsgList.
131
*-----------------------------------------------------------------------------
135
MsgList_AppendStr(MsgList **list, // IN reference to existing list
136
const char *id) // IN message ID and English message
140
/* Silently upgrade system errors to real MSGIDs. */
141
if (!Msg_HasMsgID(id) && Err_String2Errno(id) != ERR_INVALID) {
142
MsgList_Append(list, MSGID(systemerror) "%s", id);
147
* The MsgList_AppendStr variant does not accept format strings. This
148
* check disallows some legitimate strings, but it's probably easier
149
* on the msgconv parser to just disallow all format-string-like things.
151
ASSERT(strchr(id, '%') == NULL);
154
* In silent mode, skip processing in release builds. Debug
155
* builds can afford the speed cost to verify message is constructable.
157
if (list != NULL || vmx86_debug) {
158
MsgList *m = MsgId2MsgList(id);
164
/* Silent mode, but constructed as a sanity test. Clean up. */
173
*-----------------------------------------------------------------------------
177
* Create a MsgList item from the message with va_list,
178
* and attach it to the incoming list.
180
* If the incoming list pointer reference is NULL, operate in 'silent'
181
* mode: skip all work (except preconditions). Note that in silent +
182
* vmx86_debug mode, this code does all work and throws away the result,
183
* to make sure all messages are parseable.
186
* New item is attached to 'list' (and '*list' is updated).
189
* Callers are responsible to free the returned MsgList.
191
*-----------------------------------------------------------------------------
195
MsgList_VAppend(MsgList **list, // IN reference to existing list
196
const char *idFmt, // IN message ID and English message
197
va_list args) // IN args
199
ASSERT(idFmt != NULL);
201
/* Silently upgrade system errors to real MSGIDs. */
202
if (!Msg_HasMsgID(idFmt) && Err_String2Errno(idFmt) != ERR_INVALID) {
203
MsgList_Append(list, MSGID(systemerror) "%s", idFmt);
208
* In silent mode, skip processing in release builds. Debug
209
* builds can afford the speed cost to verify message is constructable.
211
if (list != NULL || vmx86_debug) {
212
MsgList *m = MsgId2MsgList(idFmt);
216
status = MsgFmt_GetArgs(m->format, args, &m->args, &m->numArgs, &error);
218
Log("%s error: %s\nformat <%s>\n", __FUNCTION__, error, m->format);
226
/* Silent mode, but constructed as a sanity test. Clean up. */
235
*-----------------------------------------------------------------------------
239
* Create the MsgList item from the message with va_list.
242
* New item is prepended to 'list' (and '*list' is new item).
245
* Callers are responsible to free the returned MsgList.
247
*-----------------------------------------------------------------------------
251
MsgList_Append(MsgList **list, // IN reference to existing list
252
const char *idFmt, // IN message ID and English message
257
va_start(args, idFmt);
258
MsgList_VAppend(list, idFmt, args);
264
*-----------------------------------------------------------------------------
268
* Create the MsgList item from the message.
271
* New MsgList structure.
274
* Callers are responsible to free the returned MsgList.
276
*-----------------------------------------------------------------------------
280
MsgList_VCreate(const char *idFmt, // IN message ID and English message
281
va_list args) // IN args
285
MsgList_VAppend(&ml, idFmt, args);
292
*-----------------------------------------------------------------------------
296
* Create the MsgList item from the message with va_list.
299
* New MsgList structure.
302
* Callers are responsible to free the returned MsgList.
304
*-----------------------------------------------------------------------------
308
MsgList_Create(const char *idFmt, // IN message ID and English message
314
va_start(args, idFmt);
315
MsgList_VAppend(&ml, idFmt, args);
323
*-----------------------------------------------------------------------------
325
* MsgList_CreateStr --
327
* Create the MsgList item from the message with no format arguments.
330
* New MsgList structure.
333
* Callers are responsible to free the returned MsgList.
335
*-----------------------------------------------------------------------------
339
MsgList_CreateStr(const char *idFmt) // IN message ID and English message
343
MsgList_AppendStr(&ml, idFmt);
350
*----------------------------------------------------------------------
354
* Makes a deep copy of the MsgList.
357
* Newly allocated MsgList. Use MsgList_Free() to free.
362
*----------------------------------------------------------------------
366
MsgList_Copy(const MsgList *src) // IN:
368
MsgList *result = NULL;
369
MsgList **pdst = &result;
371
while (src != NULL) {
372
MsgList *dst = Util_SafeMalloc(sizeof *dst);
374
dst->id = Util_SafeStrdup(src->id);
375
dst->format = Util_SafeStrdup(src->format);
376
dst->args = MsgFmt_CopyArgs(src->args, src->numArgs);
377
dst->numArgs = src->numArgs;
389
*----------------------------------------------------------------------
393
* Frees the full MsgList chain.
401
*----------------------------------------------------------------------
405
MsgList_Free(MsgList *messages) // IN:
410
for (m = messages; m != NULL; m = next) {
413
MsgFmt_FreeArgs(m->args, m->numArgs);
420
*----------------------------------------------------------------------
422
* MsgList_GetMsgID --
424
* Returns the "main" MSGID for the message stack.
426
* This is useful for Msg_Post, Msg_Hint, and Msg_Question,
427
* all of which have the semantic that the generalized MSGID
428
* is the MSGID of the last message in the stack.
431
* Returns pointer to something within the MsgList, or
432
* NULL if the MsgList doesn't exist.
437
*----------------------------------------------------------------------
441
MsgList_GetMsgID(const MsgList *messages) // IN:
443
if (messages == NULL) {
446
while (messages->next != NULL) {
447
messages = messages->next;
455
*----------------------------------------------------------------------
457
* MsgList_ToString --
459
* Returns the English representation of a MsgList chain. Does NOT
463
* Allocated memory containing message. Successive messages
464
* are separated by newlines.
469
*----------------------------------------------------------------------
473
MsgList_ToString(const MsgList *messages) // IN:
477
if (messages != NULL) {
479
char *formatted = MsgFmt_Asprintf(&len, messages->format, messages->args,
481
const char *eol = (len > 0 && formatted != NULL &&
482
formatted[len - 1] == '\n') ? "" : "\n";
485
if (messages->next != NULL) {
486
tail = MsgList_ToString(messages->next);
488
tail = Util_SafeStrdup("");
490
result = Str_SafeAsprintf(NULL, "%s%s%s", formatted, eol, tail);
500
*----------------------------------------------------------------------
504
* Emits the English representation of a MsgList chain to Log().
512
*----------------------------------------------------------------------
516
MsgList_Log(const MsgList *messages) // IN:
520
for (m = messages; m != NULL; m = m->next) {
522
char *formatted = MsgFmt_Asprintf(&len, m->format, m->args, m->numArgs);
526
(len > 0 && formatted != NULL && formatted[len - 1] == '\n') ? ""