MessageFormatter.cxx revision 7c478bd95313f5f23a4c958a745db2134aa03244
// Copyright (c) 1994, 1995, 1997 James Clark
// See the file COPYING for copying permission.
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __GNUG__
#pragma implementation
#endif
#include "splib.h"
#include "MessageFormatter.h"
#include "OutputCharStream.h"
#include "rtti.h"
#include "MessageArg.h"
#include "ErrnoMessageArg.h"
#include "SearchResultMessageArg.h"
#include "MessageFormatterMessages.h"
#include <string.h>
#include <errno.h>
#ifdef DECLARE_STRERROR
extern "C" {
char *strerror(int);
}
#endif
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
MessageFormatter::MessageFormatter()
{
}
void MessageFormatter::formatOpenElements(const Vector<OpenElementInfo> &openElementInfo,
OutputCharStream &os)
{
unsigned nOpenElements = openElementInfo.size();
for (unsigned i = 0;; i++) {
if (i > 0
&& (i == nOpenElements || openElementInfo[i].included)) {
// describe last match in previous open element
const OpenElementInfo &prevInfo = openElementInfo[i - 1];
if (prevInfo.matchType.size() != 0) {
os << " (" << prevInfo.matchType;
if (prevInfo.matchIndex != 0)
os << '[' << (unsigned long)prevInfo.matchIndex << ']';
os << ')';
}
}
if (i == nOpenElements)
break;
const OpenElementInfo &e = openElementInfo[i];
os << ' ' << e.gi;
if (i > 0 && !e.included) {
unsigned long n = openElementInfo[i - 1].matchIndex;
if (n != 0)
os << '[' << n << ']';
}
}
}
void MessageFormatter::formatMessage(const MessageFragment &frag,
const Vector<CopyOwner<MessageArg> > &args,
OutputCharStream &os)
{
StringC text;
if (!getMessageText(frag, text)) {
formatFragment(MessageFormatterMessages::invalidMessage, os);
return;
}
Builder builder(this, os, text.size() == 2);
size_t i = 0;
while (i < text.size()) {
if (text[i] == '%') {
i++;
if (i >= text.size())
break;
if (text[i] >= '1' && text[i] <= '9') {
if (unsigned(text[i] - '1') < args.size())
args[text[i] - '1']->append(builder);
}
else
os.put(text[i]);
i++;
}
else {
os.put(text[i]);
i++;
}
}
}
Boolean MessageFormatter::formatFragment(const MessageFragment &frag,
OutputCharStream &os)
{
StringC text;
if (!getMessageText(frag, text))
return 0;
os << text;
return 1;
}
void MessageFormatter::Builder::appendNumber(unsigned long n)
{
os() << n;
}
void MessageFormatter::Builder::appendOrdinal(unsigned long n)
{
os() << n;
switch (n % 10) {
case 1:
appendFragment(MessageFormatterMessages::ordinal1);
break;
case 2:
appendFragment(MessageFormatterMessages::ordinal2);
break;
case 3:
appendFragment(MessageFormatterMessages::ordinal3);
break;
default:
appendFragment(MessageFormatterMessages::ordinaln);
break;
}
}
void MessageFormatter::Builder::appendChars(const Char *p, size_t n)
{
if (argIsCompleteMessage_)
os().write(p, n);
else
os().put('"').write(p, n).put('"');
}
void MessageFormatter::Builder::appendOther(const OtherMessageArg *p)
{
const ErrnoMessageArg *ea = DYNAMIC_CAST_CONST_PTR(ErrnoMessageArg, p);
if (ea) {
os() << strerror(ea->errnum());
return;
}
const SearchResultMessageArg *sr
= DYNAMIC_CAST_CONST_PTR(SearchResultMessageArg, p);
if (sr) {
for (size_t i = 0; i < sr->nTried(); i++) {
if (i > 0)
os() << ", ";
const StringC &f = sr->filename(i);
appendChars(f.data(), f.size());
switch (sr->errnum(i)) {
default:
os() << " (";
os() << strerror(sr->errnum(i));
os() << ")";
#ifdef ENOENT
case ENOENT:
#endif
break;
}
}
return;
}
appendFragment(MessageFormatterMessages::invalidArgumentType);
}
void MessageFormatter::Builder::appendFragment(const MessageFragment &frag)
{
formatter_->formatFragment(frag, os());
}
#ifdef SP_NAMESPACE
}
#endif