0026936: Drawbacks of inlining in new type system in OCCT 7.0 -- automatic
[occt.git] / src / Message / Message_Msg.cxx
1 // Created on: 2001-04-27
2 // Created by: OCC Team
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Message_Msg.hxx>
17 #include <Message_MsgFile.hxx>
18 #include <TCollection_AsciiString.hxx>
19 #include <stdio.h>
20
21 typedef enum
22 {
23   Msg_IntegerType,
24   Msg_RealType,
25   Msg_StringType,
26   Msg_IndefiniteType
27 } FormatType;
28
29 //=======================================================================
30 //function : Message_Msg()
31 //purpose  : Constructor
32 //=======================================================================
33
34 Message_Msg::Message_Msg ()
35 {}
36
37
38 //=======================================================================
39 //function : Message_Msg()
40 //purpose  : Constructor
41 //=======================================================================
42
43 Message_Msg::Message_Msg (const Message_Msg& theMsg)
44 {
45   myMessageBody = theMsg.myMessageBody;
46   myOriginal = theMsg.myOriginal;
47   for ( Standard_Integer i = 1, n = theMsg.mySeqOfFormats.Length(); i <=n; i++ )
48     mySeqOfFormats.Append ( theMsg.mySeqOfFormats.Value(i) );
49 }
50
51 //=======================================================================
52 //function : Message_Msg()
53 //purpose  : Constructor
54 //=======================================================================
55
56 Message_Msg::Message_Msg (const Standard_CString theMsgCode)
57 {
58   TCollection_AsciiString aKey((char*)theMsgCode);
59   Set ( Message_MsgFile::Msg(aKey) );
60 }
61
62 //=======================================================================
63 //function : Message_Msg()
64 //purpose  : Constructor
65 //=======================================================================
66
67 Message_Msg::Message_Msg (const TCollection_ExtendedString& theMsgCode)
68 {
69   Set ( Message_MsgFile::Msg(theMsgCode) );
70 }
71
72 //=======================================================================
73 //function : Set
74 //purpose  : 
75 //=======================================================================
76
77 void Message_Msg::Set (const Standard_CString theMsg)
78 {
79   TCollection_AsciiString aMsg((char*)theMsg);
80   Set ( aMsg );
81 }
82
83 //=======================================================================
84 //function : Set
85 //purpose  : 
86 //=======================================================================
87
88 void Message_Msg::Set (const TCollection_ExtendedString& theMsg)
89 {
90   myMessageBody = theMsg;
91
92   const Standard_ExtString anExtString = myMessageBody.ToExtString();
93         Standard_Integer   anMsgLength = myMessageBody.Length();
94   for (Standard_Integer i = 0; i < anMsgLength; i++)
95   {
96     //  Search for '%' character starting a format specification
97     if (ToCharacter (anExtString[i]) == '%')
98     {
99       Standard_Integer   aStart = i++;
100       Standard_Character aChar = ToCharacter (anExtString[i]);
101       //        Check for format '%%'
102       if (aChar == '%')
103       {
104         myMessageBody.Remove (i+1);
105         if (i >= --anMsgLength) break;
106         aChar = ToCharacter (anExtString[i]);
107       }
108       //        Skip flags, field width and precision
109       while (i < anMsgLength)
110       {
111         if (aChar == '-' || aChar == '+' || aChar == ' ' ||
112             aChar == '#' || (aChar >= '0' && aChar <= '9') || aChar == '.')
113           i++;
114         else break;
115         aChar = ToCharacter (anExtString[i]);
116       }
117       if (i >= anMsgLength) break;
118
119       FormatType aFormatType;
120       if (aChar == 'h' || aChar == 'l') aChar = ToCharacter (anExtString[++i]);
121       switch (aChar)                    // detect the type of format spec
122       {
123       case 'd':
124       case 'i':
125       case 'o':
126       case 'u':
127       case 'x':
128       case 'X':
129         aFormatType = Msg_IntegerType;
130         break;
131       case 'f':
132       case 'e':
133       case 'E':
134       case 'g':
135       case 'G':
136         aFormatType = Msg_RealType;
137         break;
138       case 's':
139         aFormatType = Msg_StringType;
140         break;
141       default:
142         aFormatType = Msg_IndefiniteType;
143         continue;
144       }
145       mySeqOfFormats.Append (Standard_Integer(aFormatType));  // type
146       mySeqOfFormats.Append (aStart);                         // beginning pos
147       mySeqOfFormats.Append (i + 1 - aStart);                 // length
148     }
149   }
150   myOriginal = myMessageBody;
151 }
152
153 //=======================================================================
154 //function : Arg (Standard_CString)
155 //purpose  : 
156 //=======================================================================
157
158 Message_Msg& Message_Msg::Arg (const Standard_CString theString)
159 {
160   // get location and format
161   TCollection_AsciiString aFormat;
162   Standard_Integer aFirst = getFormat ( Msg_StringType, aFormat );
163   if ( !aFirst )
164     return *this;
165
166   // print string according to format
167   char * sStringBuffer = new char [Max ((Standard_Integer)strlen(theString)+1, 1024)];
168   Sprintf (sStringBuffer, aFormat.ToCString(), theString);
169   TCollection_ExtendedString aStr ( sStringBuffer, Standard_True );
170   delete [] sStringBuffer;
171   sStringBuffer = 0;
172
173   // replace the format placeholder by the actual string
174   replaceText ( aFirst, aFormat.Length(), aStr );
175   
176   return *this;
177 }
178
179 //=======================================================================
180 //function : Arg (TCollection_ExtendedString)
181 //purpose  : 
182 //remark   : This type of string is inserted without conversion (i.e. like %s)
183 //=======================================================================
184
185 Message_Msg& Message_Msg::Arg (const TCollection_ExtendedString& theString)
186 {
187   // get location and format
188   TCollection_AsciiString aFormat;
189   Standard_Integer aFirst = getFormat ( Msg_StringType, aFormat );
190   if ( !aFirst )
191     return *this;
192   
193   // replace the format placeholder by the actual string
194   replaceText ( aFirst, aFormat.Length(), theString );
195   
196   return *this;
197 }
198
199 //=======================================================================
200 //function : Arg (Standard_Integer)
201 //purpose  : 
202 //=======================================================================
203
204 Message_Msg& Message_Msg::Arg (const Standard_Integer theValue)
205 {
206   // get location and format
207   TCollection_AsciiString aFormat;
208   Standard_Integer aFirst = getFormat ( Msg_IntegerType, aFormat );
209   if ( !aFirst )
210     return *this;
211
212   // print string according to format
213   char sStringBuffer [64];
214   Sprintf (sStringBuffer, aFormat.ToCString(), theValue);
215   TCollection_ExtendedString aStr ( sStringBuffer );
216
217   // replace the format placeholder by the actual string
218   replaceText ( aFirst, aFormat.Length(), aStr );
219   
220   return *this;
221 }
222
223 //=======================================================================
224 //function : Arg (Standard_Real)
225 //purpose  : 
226 //=======================================================================
227
228 Message_Msg& Message_Msg::Arg (const Standard_Real theValue)
229 {
230   // get location and format
231   TCollection_AsciiString aFormat;
232   Standard_Integer aFirst = getFormat ( Msg_RealType, aFormat );
233   if ( !aFirst )
234     return *this;
235
236   // print string according to format
237   char sStringBuffer [64];
238   Sprintf (sStringBuffer, aFormat.ToCString(), theValue);
239   TCollection_ExtendedString aStr ( sStringBuffer );
240
241   // replace the format placeholder by the actual string
242   replaceText ( aFirst, aFormat.Length(), aStr );
243   
244   return *this;
245 }
246
247 //=======================================================================
248 //function : Get
249 //purpose  : used when the message is dispatched in Message_Messenger
250 //=======================================================================
251
252 const TCollection_ExtendedString& Message_Msg::Get ()
253 {
254   // remove all non-initialised format specifications
255   Standard_Integer i, anIncrement = 0;
256   static const TCollection_ExtendedString anUnknown ("UNKNOWN");
257   for (i = 1; i < mySeqOfFormats.Length(); i += 3)
258   {
259     TCollection_ExtendedString aRightPart =
260       myMessageBody.Split(mySeqOfFormats(i+1) + anIncrement);
261     aRightPart.Remove(1, mySeqOfFormats(i+2));
262     myMessageBody += anUnknown;
263     myMessageBody += aRightPart;
264     anIncrement += (anUnknown.Length() - mySeqOfFormats(i+2));
265   }
266   return myMessageBody;
267 }
268
269 //=======================================================================
270 //function : getFormat
271 //purpose  : Find placeholder in the string where to put next value of 
272 //           specified type, return its starting position in the string 
273 //           and relevant format string (located at that position).
274 //           The information on returned placeholder is deleted immediately,
275 //           so it will not be found further
276 //           If failed (no placeholder with relevant type found), returns 0
277 //=======================================================================
278
279 Standard_Integer Message_Msg::getFormat (const Standard_Integer theType,
280                                          TCollection_AsciiString &theFormat)
281 {
282   for (Standard_Integer i = 1; i <= mySeqOfFormats.Length(); i += 3)
283     if (mySeqOfFormats(i) == theType)
284     {
285       // Extract format
286       Standard_Integer aFirst = mySeqOfFormats(i+1);
287       Standard_Integer aLen = mySeqOfFormats(i+2);
288       theFormat = TCollection_AsciiString ( aLen, ' ' );
289       for ( Standard_Integer j=1; j <= aLen; j++ )
290         if ( IsAnAscii ( myMessageBody.Value ( aFirst + j ) ) )
291           theFormat.SetValue ( j, (Standard_Character)myMessageBody.Value ( aFirst + j ) );
292       // delete information on this placeholder
293       mySeqOfFormats.Remove (i, i+2);
294       // return start position
295       return aFirst + 1;
296     }
297   return 0;
298 }
299
300 //=======================================================================
301 //function : replaceText
302 //purpose  : Replace format text in myMessageBody (theNb chars from theFirst)
303 //           by string theStr
304 //=======================================================================
305
306 void Message_Msg::replaceText (const Standard_Integer theFirst,
307                                const Standard_Integer theNb,
308                                const TCollection_ExtendedString &theStr)
309 {
310   myMessageBody.Remove ( theFirst, theNb );
311   myMessageBody.Insert ( theFirst, theStr );
312   
313   // update information on remaining format placeholders
314   Standard_Integer anIncrement = theStr.Length() - theNb;
315   if ( ! anIncrement ) return;
316   for ( Standard_Integer i = 1; i <= mySeqOfFormats.Length(); i += 3 )
317     if ( mySeqOfFormats(i+1) > theFirst )
318       mySeqOfFormats(i+1) += anIncrement;
319 }