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