1 // Copyright (c) 1994, 1995, 1997 James Clark
2 // See the file COPYING for copying permission.
3 #pragma ident "%Z%%M% %I% %E% SMI"
4
5 #ifdef __GNUG__
6 #pragma implementation
7 #endif
8
9 #include "splib.h"
10 #include "MessageFormatter.h"
11 #include "OutputCharStream.h"
12 #include "rtti.h"
13 #include "MessageArg.h"
14 #include "ErrnoMessageArg.h"
15 #include "SearchResultMessageArg.h"
16 #include "MessageFormatterMessages.h"
17
18 #include <string.h>
19 #include <errno.h>
20
21 #ifdef DECLARE_STRERROR
22 extern "C" {
23 char *strerror(int);
24 }
25 #endif
26
27 #ifdef SP_NAMESPACE
28 namespace SP_NAMESPACE {
29 #endif
30
MessageFormatter()31 MessageFormatter::MessageFormatter()
32 {
33 }
34
formatOpenElements(const Vector<OpenElementInfo> & openElementInfo,OutputCharStream & os)35 void MessageFormatter::formatOpenElements(const Vector<OpenElementInfo> &openElementInfo,
36 OutputCharStream &os)
37 {
38 unsigned nOpenElements = openElementInfo.size();
39 for (unsigned i = 0;; i++) {
40 if (i > 0
41 && (i == nOpenElements || openElementInfo[i].included)) {
42 // describe last match in previous open element
43 const OpenElementInfo &prevInfo = openElementInfo[i - 1];
44 if (prevInfo.matchType.size() != 0) {
45 os << " (" << prevInfo.matchType;
46 if (prevInfo.matchIndex != 0)
47 os << '[' << (unsigned long)prevInfo.matchIndex << ']';
48 os << ')';
49 }
50 }
51 if (i == nOpenElements)
52 break;
53 const OpenElementInfo &e = openElementInfo[i];
54 os << ' ' << e.gi;
55 if (i > 0 && !e.included) {
56 unsigned long n = openElementInfo[i - 1].matchIndex;
57 if (n != 0)
58 os << '[' << n << ']';
59 }
60 }
61 }
62
formatMessage(const MessageFragment & frag,const Vector<CopyOwner<MessageArg>> & args,OutputCharStream & os)63 void MessageFormatter::formatMessage(const MessageFragment &frag,
64 const Vector<CopyOwner<MessageArg> > &args,
65 OutputCharStream &os)
66 {
67 StringC text;
68 if (!getMessageText(frag, text)) {
69 formatFragment(MessageFormatterMessages::invalidMessage, os);
70 return;
71 }
72 Builder builder(this, os, text.size() == 2);
73 size_t i = 0;
74 while (i < text.size()) {
75 if (text[i] == '%') {
76 i++;
77 if (i >= text.size())
78 break;
79 if (text[i] >= '1' && text[i] <= '9') {
80 if (unsigned(text[i] - '1') < args.size())
81 args[text[i] - '1']->append(builder);
82 }
83 else
84 os.put(text[i]);
85 i++;
86 }
87 else {
88 os.put(text[i]);
89 i++;
90 }
91 }
92 }
93
formatFragment(const MessageFragment & frag,OutputCharStream & os)94 Boolean MessageFormatter::formatFragment(const MessageFragment &frag,
95 OutputCharStream &os)
96 {
97 StringC text;
98 if (!getMessageText(frag, text))
99 return 0;
100 os << text;
101 return 1;
102 }
103
appendNumber(unsigned long n)104 void MessageFormatter::Builder::appendNumber(unsigned long n)
105 {
106 os() << n;
107 }
108
appendOrdinal(unsigned long n)109 void MessageFormatter::Builder::appendOrdinal(unsigned long n)
110 {
111 os() << n;
112 switch (n % 10) {
113 case 1:
114 appendFragment(MessageFormatterMessages::ordinal1);
115 break;
116 case 2:
117 appendFragment(MessageFormatterMessages::ordinal2);
118 break;
119 case 3:
120 appendFragment(MessageFormatterMessages::ordinal3);
121 break;
122 default:
123 appendFragment(MessageFormatterMessages::ordinaln);
124 break;
125 }
126 }
127
appendChars(const Char * p,size_t n)128 void MessageFormatter::Builder::appendChars(const Char *p, size_t n)
129 {
130 if (argIsCompleteMessage_)
131 os().write(p, n);
132 else
133 os().put('"').write(p, n).put('"');
134 }
135
appendOther(const OtherMessageArg * p)136 void MessageFormatter::Builder::appendOther(const OtherMessageArg *p)
137 {
138 const ErrnoMessageArg *ea = DYNAMIC_CAST_CONST_PTR(ErrnoMessageArg, p);
139
140 if (ea) {
141 os() << strerror(ea->errnum());
142 return;
143 }
144
145 const SearchResultMessageArg *sr
146 = DYNAMIC_CAST_CONST_PTR(SearchResultMessageArg, p);
147 if (sr) {
148 for (size_t i = 0; i < sr->nTried(); i++) {
149 if (i > 0)
150 os() << ", ";
151 const StringC &f = sr->filename(i);
152 appendChars(f.data(), f.size());
153 switch (sr->errnum(i)) {
154 default:
155 os() << " (";
156 os() << strerror(sr->errnum(i));
157 os() << ")";
158 #ifdef ENOENT
159 case ENOENT:
160 #endif
161 break;
162 }
163 }
164 return;
165 }
166 appendFragment(MessageFormatterMessages::invalidArgumentType);
167 }
168
appendFragment(const MessageFragment & frag)169 void MessageFormatter::Builder::appendFragment(const MessageFragment &frag)
170 {
171 formatter_->formatFragment(frag, os());
172 }
173
174 #ifdef SP_NAMESPACE
175 }
176 #endif
177