|
1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\us_des.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "us_std.h" |
|
19 |
|
20 // Terrible hack. Surely we should use VA_START instead of the below? |
|
21 #if defined(__EABI__) || (defined(__X86__) && defined(__GCC32__)) |
|
22 #define EABI_STYLE_VA_LISTS |
|
23 #endif |
|
24 |
|
25 const TInt KNoPrecision=-1; |
|
26 const TInt KDefaultPrecision=6; |
|
27 const TInt KMaxRealWidth=0x20; |
|
28 |
|
29 // TFormatedText8 and TFormatedText16 |
|
30 |
|
31 class TFormatedText8 |
|
32 { |
|
33 public: |
|
34 TBuf8<0x40> iBuffer; |
|
35 const TUint8* iText; |
|
36 TInt iTextLength; |
|
37 TInt iWidth; |
|
38 TAlign iJustify; |
|
39 TChar iFill; |
|
40 }; |
|
41 |
|
42 class TFormatedText16 |
|
43 { |
|
44 public: |
|
45 TBuf16<0x40> iBuffer; |
|
46 const TUint16* iText; |
|
47 TInt iTextLength; |
|
48 TInt iWidth; |
|
49 TAlign iJustify; |
|
50 TChar iFill; |
|
51 }; |
|
52 |
|
53 // TPanicker8 and TPanicker16 |
|
54 |
|
55 class TPanicker8 |
|
56 { |
|
57 public: |
|
58 static inline void Panic_BadFormatDescriptor() {Panic(ETDes8BadFormatDescriptor);} |
|
59 static inline void Panic_BadFormatParams() {Panic(ETDes8BadFormatParams);} |
|
60 }; |
|
61 |
|
62 class TPanicker16 |
|
63 { |
|
64 public: |
|
65 static inline void Panic_BadFormatDescriptor() {Panic(ETDes16BadFormatDescriptor);} |
|
66 static inline void Panic_BadFormatParams() {Panic(ETDes16BadFormatParams);} |
|
67 }; |
|
68 |
|
69 // TFormatDirective |
|
70 |
|
71 class TFormatDirective // basically a sort of array of parameters where the size of each parameter is stored (no more than 4 parameters are possible per format-directive) - it also knows whether the format directive it represents has an explicit index, and if so, what that index is |
|
72 { |
|
73 public: |
|
74 inline TFormatDirective() :iSizesOfParametersInBytes(0), iFormatDirectiveIndex(EImplicitFormatDirectiveIndex) {} |
|
75 void AppendParameter(TInt aSizeOfParameterInBytes,TInt aParameterAlignment); |
|
76 inline void FormatDirectiveHasExplicitIndex(TInt aFormatDirectiveIndex) {iFormatDirectiveIndex=aFormatDirectiveIndex;} |
|
77 private: |
|
78 friend class TParameterManager; |
|
79 private: |
|
80 enum {EImplicitFormatDirectiveIndex=-1}; |
|
81 enum |
|
82 { |
|
83 EShiftToNumberOfParameters=28, |
|
84 ENumberOfBitsPerParameter=5, |
|
85 EMaskForSingleParameter=(1<<ENumberOfBitsPerParameter)-1, |
|
86 EMaskForAlignmentShift=3, |
|
87 EMaskForParameterSize=EMaskForSingleParameter&~EMaskForAlignmentShift, |
|
88 EMaximumNumberOfParameters=EShiftToNumberOfParameters/ENumberOfBitsPerParameter |
|
89 }; |
|
90 private: // these functions are used by the TParameterManager class |
|
91 inline TInt NumberOfParameters() const {return iSizesOfParametersInBytes>>EShiftToNumberOfParameters;} |
|
92 TInt SizeOfParameter(TInt aIndex) const; |
|
93 TUint8* CalculateDataPointer(const TUint8* aDataPtr,TInt aIndex) const; |
|
94 private: |
|
95 TUint iSizesOfParametersInBytes; // a compactly stored array |
|
96 TInt iFormatDirectiveIndex; |
|
97 }; |
|
98 |
|
99 void TFormatDirective::AppendParameter(TInt aSizeOfParameterInBytes, TInt aParameterAlignment) |
|
100 { |
|
101 const TInt numberOfParameters=NumberOfParameters(); |
|
102 __ASSERT_DEBUG(numberOfParameters<EMaximumNumberOfParameters, Panic(ENumberOfParametersExceedsMaximum)); |
|
103 __ASSERT_DEBUG((aSizeOfParameterInBytes&EMaskForParameterSize)==aSizeOfParameterInBytes, Panic(ESizeOfParameterTooBig)); |
|
104 iSizesOfParametersInBytes+=(1<<EShiftToNumberOfParameters); // increment the count |
|
105 |
|
106 switch(aParameterAlignment) |
|
107 { |
|
108 case 4: |
|
109 // aSizeOfParameterInBytes |= 0; |
|
110 break; |
|
111 case 8: |
|
112 aSizeOfParameterInBytes |= 1; |
|
113 break; |
|
114 default: |
|
115 __ASSERT_DEBUG(0, Panic(EUnexpectedError3)); |
|
116 } |
|
117 |
|
118 iSizesOfParametersInBytes|=(aSizeOfParameterInBytes<<(numberOfParameters*ENumberOfBitsPerParameter)); // store aSizeOfParameterInBytes |
|
119 } |
|
120 |
|
121 TInt TFormatDirective::SizeOfParameter(TInt aIndex) const |
|
122 { |
|
123 __ASSERT_DEBUG(aIndex<NumberOfParameters(), Panic(EParameterIndexOutOfRange1)); |
|
124 return (iSizesOfParametersInBytes>>(aIndex*ENumberOfBitsPerParameter))&EMaskForParameterSize; |
|
125 } |
|
126 |
|
127 TUint8* TFormatDirective::CalculateDataPointer(const TUint8* aDataPtr,TInt aIndex) const |
|
128 { |
|
129 TInt numParams = NumberOfParameters(); |
|
130 __ASSERT_DEBUG(aIndex<=numParams, Panic(EParameterIndexOutOfRange1)); |
|
131 TInt paramInfo = iSizesOfParametersInBytes; |
|
132 while(numParams--) |
|
133 { |
|
134 TInt alignMask = (4<<(paramInfo&EMaskForAlignmentShift))-1; |
|
135 aDataPtr = (TUint8*)(((TInt)aDataPtr+alignMask)&~alignMask); |
|
136 if(!aIndex--) |
|
137 break; |
|
138 aDataPtr += paramInfo&EMaskForParameterSize; |
|
139 paramInfo >>= ENumberOfBitsPerParameter; |
|
140 } |
|
141 return const_cast<TUint8*>(aDataPtr); |
|
142 } |
|
143 |
|
144 // TParameterManager |
|
145 |
|
146 class TParameterManager |
|
147 { |
|
148 public: |
|
149 TParameterManager(); |
|
150 void AddFormatDirective(const TFormatDirective& aFormatDirective); |
|
151 TInt PrepareToExtractNextParameter(VA_LIST aList); // returns either KErrNone or KErrNotReady |
|
152 void PrepareToExtractParameters(VA_LIST aList); |
|
153 TInt ExtractParameter(TAny* aTarget, TInt aSizeOfParameterInBytes, TInt aFormatDirectiveIndex, TInt aParameterIndexWithinFormatDirective, const TFormatDirective* aNextFormatDirective); |
|
154 private: |
|
155 enum |
|
156 { |
|
157 EMaximumNumberOfFormatDirectives=40, |
|
158 ENumberOfBytesInBitArray=(EMaximumNumberOfFormatDirectives+7)/8 |
|
159 }; |
|
160 private: |
|
161 inline TBool FormatDirectiveIsSet(TInt aIndex) const {return iFormatDirectivesSet[aIndex/8]&(1<<(aIndex%8));} |
|
162 inline void MarkFormatDirectiveAsSet(TInt aIndex) {iFormatDirectivesSet[aIndex/8]|=(1<<(aIndex%8)); __ASSERT_DEBUG(FormatDirectiveIsSet(aIndex), Panic(EFormatDirectiveAlreadySet1));} |
|
163 private: |
|
164 TInt iNumberOfFormatDirectives; |
|
165 TFixedArray<TUint8, ENumberOfBytesInBitArray> iFormatDirectivesSet; |
|
166 TFixedArray<TFormatDirective, EMaximumNumberOfFormatDirectives> iFormatDirectives; |
|
167 TFixedArray<const TUint8*, EMaximumNumberOfFormatDirectives> iFormatDirectiveDataPointers; |
|
168 }; |
|
169 |
|
170 TParameterManager::TParameterManager() |
|
171 :iNumberOfFormatDirectives(0) |
|
172 { |
|
173 TInt i; |
|
174 for (i=0; i<ENumberOfBytesInBitArray; ++i) |
|
175 { |
|
176 iFormatDirectivesSet[i]=0; |
|
177 } |
|
178 for (i=0; i<EMaximumNumberOfFormatDirectives; ++i) |
|
179 { |
|
180 iFormatDirectiveDataPointers[i]=NULL; |
|
181 } |
|
182 } |
|
183 |
|
184 void TParameterManager::AddFormatDirective(const TFormatDirective& aFormatDirective) |
|
185 { |
|
186 __ASSERT_ALWAYS(iNumberOfFormatDirectives<EMaximumNumberOfFormatDirectives, Panic(ENumberOfFormatDirectivesExceedsMaximum)); |
|
187 const TInt index=(aFormatDirective.iFormatDirectiveIndex>=0)? aFormatDirective.iFormatDirectiveIndex: iNumberOfFormatDirectives; |
|
188 __ASSERT_ALWAYS(!FormatDirectiveIsSet(index), Panic(EFormatDirectiveAlreadySet2)); |
|
189 MarkFormatDirectiveAsSet(index); |
|
190 iFormatDirectives[index]=aFormatDirective; |
|
191 ++iNumberOfFormatDirectives; |
|
192 } |
|
193 |
|
194 TInt TParameterManager::PrepareToExtractNextParameter(VA_LIST aList) |
|
195 { |
|
196 if (iNumberOfFormatDirectives==0) |
|
197 { |
|
198 #ifdef EABI_STYLE_VA_LISTS |
|
199 // NB under the EABI we are passing va_list (a struct) by value. |
|
200 // We could extract the pointer using aList.__ap under RVCT, but I don't believe the EABI |
|
201 // extends to the name of the field. So I think the 'nasty' cast is likely to be more |
|
202 // portable. |
|
203 const TUint8 ** aL = (const TUint8**)&aList; |
|
204 iFormatDirectiveDataPointers[iNumberOfFormatDirectives] = aL[0]; |
|
205 #else |
|
206 // The horrible cast is there because you can't assume aList is of 'array' type |
|
207 iFormatDirectiveDataPointers[iNumberOfFormatDirectives] = (const TUint8*)(*(TInt*)aList); |
|
208 #endif |
|
209 } |
|
210 else |
|
211 { |
|
212 const TInt previousFormatDirective=iNumberOfFormatDirectives-1; |
|
213 const TUint8* dataPointer=iFormatDirectiveDataPointers[previousFormatDirective]; |
|
214 if ((dataPointer==NULL) || !FormatDirectiveIsSet(previousFormatDirective)) |
|
215 { |
|
216 return KErrNotReady; |
|
217 } |
|
218 const TFormatDirective& formatDirective=iFormatDirectives[previousFormatDirective]; |
|
219 dataPointer = formatDirective.CalculateDataPointer(dataPointer,formatDirective.NumberOfParameters()); |
|
220 iFormatDirectiveDataPointers[iNumberOfFormatDirectives]=dataPointer; |
|
221 } |
|
222 return KErrNone; |
|
223 } |
|
224 |
|
225 void TParameterManager::PrepareToExtractParameters(VA_LIST aList) |
|
226 { |
|
227 #ifdef EABI_STYLE_VA_LISTS |
|
228 // NB under the EABI we are passing va_list (a struct) by value. |
|
229 // We could extract the pointer using aList.__ap under RVCT, but I don't believe the EABI |
|
230 // extends to the name of the field. So I think the 'nasty' cast is likely to be more |
|
231 // portable. |
|
232 const TUint8 ** aL = (const TUint8**)&aList; |
|
233 const TUint8* dataPointer = aL[0]; |
|
234 #else |
|
235 // The horrible cast is there because you can't assume aList is of 'array' type |
|
236 const TUint8* dataPointer = (const TUint8*)(*(TInt*)aList); |
|
237 #endif |
|
238 if (iNumberOfFormatDirectives>0) |
|
239 { |
|
240 for (TInt i=0; ; ++i) |
|
241 { |
|
242 __ASSERT_ALWAYS(FormatDirectiveIsSet(i), Panic(EFormatDirectiveNotYetSet)); |
|
243 __ASSERT_DEBUG((iFormatDirectiveDataPointers[i]==NULL) || (iFormatDirectiveDataPointers[i]==dataPointer), Panic(EBadFormatDirectiveDataPointer)); |
|
244 iFormatDirectiveDataPointers[i]=dataPointer; |
|
245 if (i+1>=iNumberOfFormatDirectives) |
|
246 { |
|
247 break; |
|
248 } |
|
249 const TFormatDirective& formatDirective=iFormatDirectives[i]; |
|
250 dataPointer = formatDirective.CalculateDataPointer(dataPointer,formatDirective.NumberOfParameters()); |
|
251 } |
|
252 } |
|
253 } |
|
254 |
|
255 TInt TParameterManager::ExtractParameter(TAny* aTarget, TInt aSizeOfParameterInBytes, TInt aFormatDirectiveIndex, TInt aParameterIndexWithinFormatDirective, const TFormatDirective* aNextFormatDirective) |
|
256 { |
|
257 __ASSERT_DEBUG(aFormatDirectiveIndex<EMaximumNumberOfFormatDirectives, Panic(EFormatDirectiveIndexOutOfRange)); |
|
258 const TFormatDirective* formatDirective=NULL; |
|
259 if (aFormatDirectiveIndex<iNumberOfFormatDirectives) |
|
260 { |
|
261 if (!FormatDirectiveIsSet(aFormatDirectiveIndex)) |
|
262 { |
|
263 return KErrNotReady; |
|
264 } |
|
265 formatDirective=&iFormatDirectives[aFormatDirectiveIndex]; |
|
266 } |
|
267 else |
|
268 { |
|
269 __ASSERT_DEBUG(aNextFormatDirective!=NULL, Panic(ENotOnFirstPassOfFormatDescriptor1)); // the above condition (aFormatDirectiveIndex>=iNumberOfFormatDirectives) can only be the case on a first pass of the format descriptor, so assert that we're on the first pass |
|
270 if (aFormatDirectiveIndex>iNumberOfFormatDirectives) |
|
271 { |
|
272 return KErrNotReady; |
|
273 } |
|
274 formatDirective=aNextFormatDirective; |
|
275 } |
|
276 __ASSERT_DEBUG(aSizeOfParameterInBytes==formatDirective->SizeOfParameter(aParameterIndexWithinFormatDirective), Panic(EInconsistentSizeOfParameter)); |
|
277 const TUint8* dataPointer=iFormatDirectiveDataPointers[aFormatDirectiveIndex]; |
|
278 if (dataPointer==NULL) |
|
279 { |
|
280 __ASSERT_DEBUG(aNextFormatDirective!=NULL, Panic(ENotOnFirstPassOfFormatDescriptor2)); // the above condition (dataPointer==NULL) can only be the case on a first pass of the format descriptor, so assert that we're on the first pass |
|
281 return KErrNotReady; |
|
282 } |
|
283 __ASSERT_DEBUG(aParameterIndexWithinFormatDirective<formatDirective->NumberOfParameters(), Panic(EParameterIndexOutOfRange2)); |
|
284 dataPointer = formatDirective->CalculateDataPointer(dataPointer,aParameterIndexWithinFormatDirective); |
|
285 Mem::Copy(aTarget, dataPointer, aSizeOfParameterInBytes); |
|
286 return KErrNone; |
|
287 } |
|
288 |
|
289 // TParameterHandler |
|
290 |
|
291 class TParameterHandler |
|
292 { |
|
293 public: |
|
294 enum TAction |
|
295 { |
|
296 EParameterNotExtracted, |
|
297 EParameterExtracted |
|
298 }; |
|
299 public: |
|
300 inline TParameterHandler(TInt aImplicitFormatDirectiveIndex, TParameterManager& aParameterManager, TFormatDirective& aFormatDirective) :iFormatDirectiveIndex(aImplicitFormatDirectiveIndex), iParameterIndex(0), iFormatDirective(&aFormatDirective), iParameterManager(aParameterManager) {} // for the first pass |
|
301 inline TParameterHandler(TInt aImplicitFormatDirectiveIndex, TParameterManager& aParameterManager) :iFormatDirectiveIndex(aImplicitFormatDirectiveIndex), iParameterIndex(0), iFormatDirective(NULL), iParameterManager(aParameterManager) {} // for the second pass |
|
302 TAction HandleParameter(TAny* aTarget, TInt aSizeOfParameterInBytes, TInt aParameterAlignment=4); |
|
303 void FormatDirectiveHasExplicitIndex(TInt aFormatDirectiveIndex); |
|
304 private: |
|
305 TInt iFormatDirectiveIndex; |
|
306 TInt iParameterIndex; |
|
307 TFormatDirective* iFormatDirective; |
|
308 TParameterManager& iParameterManager; |
|
309 }; |
|
310 |
|
311 TParameterHandler::TAction TParameterHandler::HandleParameter(TAny* aTarget, TInt aSizeOfParameterInBytes, TInt aParameterAlignment) |
|
312 // Increments iParameterIndex each time it is called. |
|
313 // This is conceptually a sort of virtual function (i.e. it's behaviour depends on the way the object was constructed), although it is not implemented like that. |
|
314 { |
|
315 __ASSERT_DEBUG(aTarget!=NULL, Panic(ENullTargetPointer)); |
|
316 __ASSERT_DEBUG(aSizeOfParameterInBytes>=0, Panic(ENegativeSizeOfParameter)); |
|
317 const TUint machineWordAlignmentConstant=sizeof(TUint)-1; |
|
318 aSizeOfParameterInBytes+=machineWordAlignmentConstant; |
|
319 aSizeOfParameterInBytes&=~machineWordAlignmentConstant; |
|
320 |
|
321 if (iFormatDirective!=NULL) |
|
322 { |
|
323 iFormatDirective->AppendParameter(aSizeOfParameterInBytes,aParameterAlignment); |
|
324 } |
|
325 const TInt error=iParameterManager.ExtractParameter(aTarget, aSizeOfParameterInBytes, iFormatDirectiveIndex, iParameterIndex, iFormatDirective); |
|
326 #if defined(_DEBUG) |
|
327 if (iFormatDirective==NULL) // if we're on the second pass... |
|
328 { |
|
329 __ASSERT_DEBUG(error==KErrNone, Panic(EErrorOnSecondPassOfFormatDescriptor)); |
|
330 } |
|
331 else |
|
332 { |
|
333 __ASSERT_DEBUG(error==KErrNone || error==KErrNotReady, Panic(EUnexpectedError1)); |
|
334 } |
|
335 #endif |
|
336 ++iParameterIndex; |
|
337 return (error==KErrNone)? EParameterExtracted: EParameterNotExtracted; |
|
338 } |
|
339 |
|
340 void TParameterHandler::FormatDirectiveHasExplicitIndex(TInt aFormatDirectiveIndex) |
|
341 { |
|
342 if (iFormatDirective!=NULL) |
|
343 { |
|
344 iFormatDirective->FormatDirectiveHasExplicitIndex(aFormatDirectiveIndex); |
|
345 } |
|
346 iFormatDirectiveIndex=aFormatDirectiveIndex; |
|
347 } |
|
348 |
|
349 template <class XDesC, class XFormatedText, class XLex, class XPanicker, TInt XItemSize> |
|
350 void HandleFormatDirective(TParameterHandler& aParameterHandler, XFormatedText& aFormatedText, XLex& aFmt) |
|
351 // |
|
352 // Handle a single format directive, i.e. sequence starting with a '%', (although the initial '%' will have been consumed by this point). |
|
353 // |
|
354 { |
|
355 |
|
356 // Determine alignment of various types on the stack. The FOFF approach |
|
357 // does not work for GCC 3.4.4 on X86 so we use hardcoded constants instead. |
|
358 #if defined(__GCC32__) && defined(__X86__) |
|
359 const TInt KAlignTReal = 4; |
|
360 const TInt KAlignTRealX = 4; |
|
361 const TInt KAlignTInt64 = 4; |
|
362 #else |
|
363 struct TReal_align {char c; TReal a;}; |
|
364 const TInt KAlignTReal = _FOFF(TReal_align,a); |
|
365 #ifndef __VC32__ // MSVC generates an internal compiler error with the following code |
|
366 struct TRealX_align {char c; TRealX a;}; |
|
367 const TInt KAlignTRealX = _FOFF(TRealX_align,a); |
|
368 |
|
369 struct TInt64_align {char c; TInt64 a;}; |
|
370 const TInt KAlignTInt64 = _FOFF(TInt64_align,a); |
|
371 #else |
|
372 const TInt KAlignTRealX = 4; // Hard code value for MSVC |
|
373 const TInt KAlignTInt64 = 4; // Hard code value for MSVC |
|
374 #endif |
|
375 #endif |
|
376 |
|
377 aFormatedText.iJustify=ERight; // Default is justify right |
|
378 aFormatedText.iFill=KNoChar; // Default fill character is space |
|
379 // After a % may come +,-,= or space |
|
380 if (aFmt.Eos()) |
|
381 XPanicker::Panic_BadFormatDescriptor(); |
|
382 TChar c=aFmt.Get(); |
|
383 |
|
384 if (c=='$') |
|
385 { |
|
386 TInt formatDirectiveIndex; |
|
387 if (aFmt.Val(formatDirectiveIndex)!=0) |
|
388 XPanicker::Panic_BadFormatDescriptor(); |
|
389 aParameterHandler.FormatDirectiveHasExplicitIndex(formatDirectiveIndex-1); |
|
390 if (aFmt.Get()!='$') |
|
391 XPanicker::Panic_BadFormatDescriptor(); |
|
392 c=aFmt.Get(); |
|
393 } |
|
394 |
|
395 switch (c) |
|
396 { |
|
397 case ' ': |
|
398 aFormatedText.iFill=' '; |
|
399 break; |
|
400 case '-': |
|
401 aFormatedText.iJustify=ELeft; |
|
402 goto getFill; |
|
403 case '=': |
|
404 aFormatedText.iJustify=ECenter; |
|
405 goto getFill; |
|
406 case '+': |
|
407 getFill: |
|
408 if (aFmt.Eos()) |
|
409 XPanicker::Panic_BadFormatDescriptor(); |
|
410 if (!aFmt.Peek().IsDigit()) |
|
411 { |
|
412 aFormatedText.iFill=aFmt.Get(); // assigning aFormatedText.iFill to something other than KNoChar is necessary as the aParameterHandler.HandleParameter call a couple of lines below will not necessarily set its first parameter (i.e. aFormatedText.iFill) - aFormatedText.iFill is tested against KNoChar ten or so lines below |
|
413 if (aFormatedText.iFill=='*') // If* take it from the arguments |
|
414 aParameterHandler.HandleParameter(&aFormatedText.iFill, sizeof(TUint)); |
|
415 } |
|
416 break; |
|
417 default: |
|
418 aFmt.UnGet(); |
|
419 } |
|
420 |
|
421 aFormatedText.iWidth=KDefaultJustifyWidth; // Default width is whatever the conversion takes |
|
422 if (aFmt.Peek().IsDigit()) |
|
423 { |
|
424 // If it starts with 0 and the fill character has not been |
|
425 // specified then the fill character will be a 0 |
|
426 // For compatibility with standard C libraries |
|
427 if (aFmt.Peek()=='0' && aFormatedText.iFill==KNoChar) |
|
428 { |
|
429 aFormatedText.iFill='0'; |
|
430 aFmt.Inc(); |
|
431 } |
|
432 if (aFmt.Peek()!='*') |
|
433 if (aFmt.Val(aFormatedText.iWidth)) // Convert field width value |
|
434 XPanicker::Panic_BadFormatDescriptor(); |
|
435 } |
|
436 if (aFmt.Peek()=='*' && aFormatedText.iWidth==KDefaultJustifyWidth) // If a * then get width from arguments |
|
437 { |
|
438 aParameterHandler.HandleParameter(&aFormatedText.iWidth, sizeof(TInt)); |
|
439 aFmt.Inc(); |
|
440 } |
|
441 // Get precision setting if given |
|
442 TInt precision=KNoPrecision; |
|
443 if (aFmt.Peek()=='.') |
|
444 { |
|
445 aFmt.Inc(); |
|
446 if (aFmt.Peek()=='*') |
|
447 { |
|
448 aParameterHandler.HandleParameter(&precision, sizeof(TInt)); |
|
449 aFmt.Inc(); |
|
450 } |
|
451 else if (aFmt.Val(precision)) |
|
452 XPanicker::Panic_BadFormatDescriptor(); |
|
453 } |
|
454 if (aFormatedText.iFill==KNoChar) // If still default fill character make it space |
|
455 aFormatedText.iFill=' '; |
|
456 if (aFmt.Eos()) |
|
457 XPanicker::Panic_BadFormatDescriptor(); |
|
458 TChar selector; |
|
459 TBool lng=EFalse; |
|
460 TCharUC f=aFmt.Peek(); |
|
461 if (f=='L') // If l set selector for longs |
|
462 { |
|
463 aFmt.Inc(); |
|
464 lng=ETrue; |
|
465 } |
|
466 selector=aFmt.Get(); // Get the selector in upper case |
|
467 aFormatedText.iText=aFormatedText.iBuffer.Ptr(); |
|
468 aFormatedText.iTextLength=1; |
|
469 TRadix radix=EDecimal; |
|
470 TUint uVal=0; |
|
471 TReal rVal=0; |
|
472 TRealX rValX=0; |
|
473 TInt realFormatType=KRealFormatFixed; |
|
474 switch (selector) |
|
475 { |
|
476 case 'S': // String conversion |
|
477 { |
|
478 const XDesC* pB; |
|
479 if (aParameterHandler.HandleParameter(&pB, sizeof(const TAny*))==TParameterHandler::EParameterExtracted) |
|
480 { |
|
481 __ASSERT_DEBUG(pB!=0,XPanicker::Panic_BadFormatParams()); |
|
482 aFormatedText.iTextLength=pB->Length(); |
|
483 if (precision!=KNoPrecision && precision<aFormatedText.iTextLength) |
|
484 aFormatedText.iTextLength=precision; |
|
485 aFormatedText.iText=pB->Ptr(); |
|
486 } |
|
487 } |
|
488 break; |
|
489 case 's': |
|
490 if (aParameterHandler.HandleParameter(&aFormatedText.iText, sizeof(const TAny*))==TParameterHandler::EParameterExtracted) |
|
491 { |
|
492 __ASSERT_DEBUG(aFormatedText.iText!=0,XPanicker::Panic_BadFormatParams()); |
|
493 if (precision!=KNoPrecision) |
|
494 aFormatedText.iTextLength=precision; |
|
495 else |
|
496 aFormatedText.iTextLength=User::StringLength(aFormatedText.iText); |
|
497 } |
|
498 break; |
|
499 case 'O': |
|
500 case 'o': |
|
501 radix=EOctal; |
|
502 goto lConv; |
|
503 case 'X': |
|
504 case 'x': |
|
505 radix=EHex; |
|
506 goto lConv; |
|
507 case 'B': // Binary conversion |
|
508 case 'b': |
|
509 radix=EBinary; |
|
510 // Fall-through to lConv |
|
511 case 'U': |
|
512 case 'u': |
|
513 lConv: |
|
514 if (lng) |
|
515 { |
|
516 TInt64 uVal64 = 0; |
|
517 if (aParameterHandler.HandleParameter(&uVal64, sizeof(TInt64), KAlignTInt64)==TParameterHandler::EParameterExtracted) |
|
518 { |
|
519 if (selector=='X') |
|
520 aFormatedText.iBuffer.NumUC(uVal64,radix); |
|
521 else |
|
522 aFormatedText.iBuffer.Num(uVal64,radix); |
|
523 } |
|
524 } |
|
525 else |
|
526 { |
|
527 if (aParameterHandler.HandleParameter(&uVal, sizeof(TUint))==TParameterHandler::EParameterExtracted) |
|
528 { |
|
529 if (selector=='X') |
|
530 aFormatedText.iBuffer.NumUC(uVal,radix); |
|
531 else |
|
532 aFormatedText.iBuffer.Num(uVal,radix); |
|
533 } |
|
534 } |
|
535 aFormatedText.iTextLength=aFormatedText.iBuffer.Length(); |
|
536 break; |
|
537 case 'D': // Decimal conversion |
|
538 case 'd': |
|
539 case 'I': |
|
540 case 'i': |
|
541 if (lng) |
|
542 { |
|
543 TInt64 iVal64=0; |
|
544 if (aParameterHandler.HandleParameter(&iVal64, sizeof(TInt64),KAlignTInt64)==TParameterHandler::EParameterExtracted) |
|
545 { |
|
546 aFormatedText.iBuffer.Num(iVal64); |
|
547 } |
|
548 } |
|
549 else |
|
550 { |
|
551 TInt iVal=0; |
|
552 if (aParameterHandler.HandleParameter(&iVal, sizeof(TInt))==TParameterHandler::EParameterExtracted) |
|
553 { |
|
554 aFormatedText.iBuffer.Num(iVal); |
|
555 } |
|
556 } |
|
557 aFormatedText.iTextLength=aFormatedText.iBuffer.Length(); |
|
558 break; |
|
559 case 'P': // Padded conversion |
|
560 case 'p': |
|
561 aFormatedText.iTextLength=0; |
|
562 break; |
|
563 case 'C': |
|
564 case 'c': // Ascii character conversion |
|
565 if (aParameterHandler.HandleParameter(&uVal, sizeof(TUint))==TParameterHandler::EParameterExtracted) |
|
566 { |
|
567 aFormatedText.iBuffer.Append(uVal); |
|
568 } |
|
569 break; |
|
570 case 'W': // SLONG binary lsb first conversion |
|
571 case 'M': // SLONG binary msb first conversion |
|
572 if (aParameterHandler.HandleParameter(&uVal, sizeof(TUint))!=TParameterHandler::EParameterExtracted) |
|
573 { |
|
574 break; |
|
575 } |
|
576 aFormatedText.iTextLength=4/XItemSize; |
|
577 goto doBinary; |
|
578 case 'w': // SWORD binary lsb first conversion |
|
579 case 'm': // SWORD binary msb first conversion |
|
580 if (aParameterHandler.HandleParameter(&uVal, sizeof(TUint))!=TParameterHandler::EParameterExtracted) |
|
581 { |
|
582 break; |
|
583 } |
|
584 aFormatedText.iTextLength=2/XItemSize; |
|
585 //goto doBinary; |
|
586 doBinary: |
|
587 { |
|
588 TUint8* pC; |
|
589 TInt increment; |
|
590 if (selector=='m' || selector=='M') |
|
591 { |
|
592 pC=((TUint8*)(aFormatedText.iText+aFormatedText.iTextLength))-1; |
|
593 increment=(-1); |
|
594 } |
|
595 else |
|
596 { |
|
597 pC=(TUint8*)aFormatedText.iText; |
|
598 increment=1; |
|
599 } |
|
600 for (TInt k=aFormatedText.iTextLength*sizeof(*aFormatedText.iText);k>0;--k) |
|
601 { |
|
602 *pC=(TUint8)uVal; |
|
603 pC+=increment; |
|
604 uVal>>=8; |
|
605 } |
|
606 } |
|
607 break; |
|
608 case 'F': // TRealX conversion |
|
609 if (aParameterHandler.HandleParameter(&rValX, sizeof(TRealX), KAlignTRealX)!=TParameterHandler::EParameterExtracted) |
|
610 { |
|
611 break; |
|
612 } |
|
613 rVal=rValX; |
|
614 goto doReal; |
|
615 case 'f': // TReal conversion |
|
616 if (aParameterHandler.HandleParameter(&rVal, sizeof(TReal), KAlignTReal)!=TParameterHandler::EParameterExtracted) |
|
617 { |
|
618 break; |
|
619 } |
|
620 goto doReal; |
|
621 case 'E': |
|
622 if (aParameterHandler.HandleParameter(&rValX, sizeof(TRealX), KAlignTRealX)!=TParameterHandler::EParameterExtracted) |
|
623 { |
|
624 break; |
|
625 } |
|
626 rVal=rValX; |
|
627 realFormatType=KRealFormatExponent|KAllowThreeDigitExp; // AnnW - changed from EExponent |
|
628 goto doReal; |
|
629 case 'e': |
|
630 if (aParameterHandler.HandleParameter(&rVal, sizeof(TReal), KAlignTReal)!=TParameterHandler::EParameterExtracted) |
|
631 { |
|
632 break; |
|
633 } |
|
634 realFormatType=KRealFormatExponent|KAllowThreeDigitExp; // AnnW - changed from EExponent |
|
635 //goto doReal; |
|
636 doReal: |
|
637 { |
|
638 if (precision==KNoPrecision) |
|
639 precision=KDefaultPrecision; |
|
640 TRealFormat realFormat(KMaxRealWidth, precision); |
|
641 realFormat.iType=realFormatType; |
|
642 aFormatedText.iTextLength=aFormatedText.iBuffer.Num(rVal, realFormat); |
|
643 if (aFormatedText.iTextLength<0) |
|
644 { |
|
645 if (aFormatedText.iTextLength==KErrGeneral) |
|
646 XPanicker::Panic_BadFormatDescriptor(); |
|
647 else |
|
648 aFormatedText.iTextLength=aFormatedText.iBuffer.Length(); |
|
649 } |
|
650 if (aFormatedText.iWidth!=KDefaultJustifyWidth && aFormatedText.iTextLength>aFormatedText.iWidth) |
|
651 aFormatedText.iWidth=aFormatedText.iTextLength; |
|
652 } |
|
653 break; |
|
654 case 'G': |
|
655 if (aParameterHandler.HandleParameter(&rValX, sizeof(TRealX), KAlignTRealX)!=TParameterHandler::EParameterExtracted) |
|
656 { |
|
657 break; |
|
658 } |
|
659 rVal=rValX; |
|
660 goto doGReal; |
|
661 case 'g': |
|
662 if (aParameterHandler.HandleParameter(&rVal, sizeof(TReal), KAlignTReal)!=TParameterHandler::EParameterExtracted) |
|
663 { |
|
664 break; |
|
665 } |
|
666 //goto doGReal; |
|
667 doGReal: |
|
668 { |
|
669 if (precision==KNoPrecision) |
|
670 precision=KDefaultPrecision; |
|
671 |
|
672 // aFormatedText.iBuffer must be >= KMaxRealWidth |
|
673 TRealFormat realFormat(KMaxRealWidth, precision); // Changed from 'width' to KMaxRealWidth |
|
674 realFormat.iType=KRealFormatGeneral|KAllowThreeDigitExp; // AnnW - changed from EGeneral |
|
675 aFormatedText.iTextLength=aFormatedText.iBuffer.Num(rVal, realFormat); |
|
676 if (aFormatedText.iTextLength<0) |
|
677 { |
|
678 // Doesn't fit in given width |
|
679 realFormat.iWidth=KDefaultRealWidth; |
|
680 aFormatedText.iTextLength=aFormatedText.iBuffer.Num(rVal, realFormat); |
|
681 } |
|
682 if (aFormatedText.iTextLength<0) |
|
683 { |
|
684 if (aFormatedText.iTextLength==KErrGeneral) |
|
685 XPanicker::Panic_BadFormatDescriptor(); |
|
686 else |
|
687 aFormatedText.iTextLength=aFormatedText.iBuffer.Length(); |
|
688 } |
|
689 if (aFormatedText.iWidth!=KDefaultJustifyWidth && aFormatedText.iTextLength>aFormatedText.iWidth) |
|
690 aFormatedText.iWidth=aFormatedText.iTextLength; |
|
691 } |
|
692 break; |
|
693 default: // Not recognized - output % something |
|
694 XPanicker::Panic_BadFormatDescriptor(); |
|
695 } |
|
696 // Justify result of conversion |
|
697 if (aFormatedText.iWidth==KDefaultJustifyWidth) |
|
698 aFormatedText.iWidth=aFormatedText.iTextLength; |
|
699 if (aFormatedText.iTextLength>aFormatedText.iWidth) |
|
700 aFormatedText.iTextLength=aFormatedText.iWidth; |
|
701 } |
|
702 |
|
703 template <class XDes, class XDesOverflow, class XDesC, class XFormatedText, class XLex, class XPanicker, TInt XItemSize> |
|
704 void DoAppendFormatList(XDes& aThis,const XDesC& aFormat,VA_LIST aList,XDesOverflow* aOverflowHandler) |
|
705 // |
|
706 // Convert the argument list, using the format descriptor. |
|
707 // |
|
708 { |
|
709 |
|
710 const TInt overflowLength=aOverflowHandler? aThis.MaxLength(): KMaxTInt; |
|
711 const TInt originalLength=aThis.Length(); |
|
712 TBool needSecondPass=EFalse; |
|
713 TParameterManager parameterManager; |
|
714 XLex format(aFormat); |
|
715 TInt implicitFormatDirectiveIndex=0; |
|
716 FOREVER |
|
717 { |
|
718 if (format.Eos()) |
|
719 { |
|
720 break; |
|
721 } |
|
722 const TChar character=format.Get(); |
|
723 if (character!='%') |
|
724 { |
|
725 if (!needSecondPass) |
|
726 { |
|
727 if (aThis.Length()>=overflowLength) |
|
728 { |
|
729 aOverflowHandler->Overflow(aThis); |
|
730 return; |
|
731 } |
|
732 aThis.Append(character); |
|
733 } |
|
734 } |
|
735 else if (format.Peek()=='%') |
|
736 { |
|
737 if (!needSecondPass) |
|
738 { |
|
739 if (aThis.Length()>=overflowLength) |
|
740 { |
|
741 aOverflowHandler->Overflow(aThis); |
|
742 return; |
|
743 } |
|
744 aThis.Append(character); |
|
745 } |
|
746 format.Inc(); |
|
747 } |
|
748 else |
|
749 { |
|
750 TFormatDirective formatDirective; |
|
751 TParameterHandler parameterHandler(implicitFormatDirectiveIndex, parameterManager, formatDirective); |
|
752 XFormatedText formatedText; |
|
753 const TInt error=parameterManager.PrepareToExtractNextParameter(aList); |
|
754 if (error!=KErrNone) |
|
755 { |
|
756 __ASSERT_DEBUG(error==KErrNotReady, Panic(EUnexpectedError2)); |
|
757 needSecondPass=ETrue; |
|
758 } |
|
759 HandleFormatDirective<XDesC, XFormatedText, XLex, XPanicker, XItemSize>(parameterHandler, formatedText, format); |
|
760 parameterManager.AddFormatDirective(formatDirective); |
|
761 if (!needSecondPass) |
|
762 { |
|
763 if ((aThis.Length()+formatedText.iWidth)>overflowLength) |
|
764 { |
|
765 aOverflowHandler->Overflow(aThis); |
|
766 return; |
|
767 } |
|
768 aThis.AppendJustify(formatedText.iText, formatedText.iTextLength, formatedText.iWidth, formatedText.iJustify, formatedText.iFill); |
|
769 } |
|
770 ++implicitFormatDirectiveIndex; |
|
771 } |
|
772 } |
|
773 if (needSecondPass) |
|
774 { |
|
775 aThis.SetLength(originalLength); |
|
776 parameterManager.PrepareToExtractParameters(aList); |
|
777 format=aFormat; |
|
778 implicitFormatDirectiveIndex=0; |
|
779 FOREVER |
|
780 { |
|
781 if (format.Eos()) |
|
782 { |
|
783 break; |
|
784 } |
|
785 const TChar character=format.Get(); |
|
786 if (character!='%') |
|
787 { |
|
788 if (aThis.Length()>=overflowLength) |
|
789 { |
|
790 aOverflowHandler->Overflow(aThis); |
|
791 return; |
|
792 } |
|
793 aThis.Append(character); |
|
794 } |
|
795 else if (format.Peek()=='%') |
|
796 { |
|
797 if (aThis.Length()>=overflowLength) |
|
798 { |
|
799 aOverflowHandler->Overflow(aThis); |
|
800 return; |
|
801 } |
|
802 aThis.Append(character); |
|
803 format.Inc(); |
|
804 } |
|
805 else |
|
806 { |
|
807 TParameterHandler parameterHandler(implicitFormatDirectiveIndex, parameterManager); |
|
808 XFormatedText formatedText; |
|
809 HandleFormatDirective<XDesC, XFormatedText, XLex, XPanicker, XItemSize>(parameterHandler, formatedText, format); |
|
810 if ((aThis.Length()+formatedText.iWidth)>overflowLength) |
|
811 { |
|
812 aOverflowHandler->Overflow(aThis); |
|
813 return; |
|
814 } |
|
815 aThis.AppendJustify(formatedText.iText, formatedText.iTextLength, formatedText.iWidth, formatedText.iJustify, formatedText.iFill); |
|
816 ++implicitFormatDirectiveIndex; |
|
817 } |
|
818 } |
|
819 } |
|
820 } |
|
821 |
|
822 |
|
823 |
|
824 |
|
825 /** |
|
826 Formats and appends text onto the end of this descriptor's data. |
|
827 |
|
828 The length of this descriptor is incremented to reflect the new content. |
|
829 |
|
830 The behaviour of this function is the same as |
|
831 AppendFormat(TRefByValue<const TDesC8> aFmt,TDes8Overflow *aOverflowHandler,...). |
|
832 In practice, it is better and easier to use AppendFormat(), passing a variable number of |
|
833 arguments as required by the format string. |
|
834 |
|
835 @param aFormat The descriptor containing the format string. |
|
836 @param aList A pointer to an argument list. |
|
837 @param aOverflowHandler If supplied, a pointer to the overflow handler. |
|
838 |
|
839 @see TDes8::AppendFormat |
|
840 @see VA_LIST |
|
841 */ |
|
842 EXPORT_C void TDes8::AppendFormatList(const TDesC8 &aFormat,VA_LIST aList,TDes8Overflow *aOverflowHandler) |
|
843 { |
|
844 |
|
845 DoAppendFormatList<TDes8, TDes8Overflow, TDesC8, TFormatedText8, TLex8, TPanicker8, sizeof(TUint8)>(*this,aFormat,aList,aOverflowHandler); |
|
846 } |
|
847 |
|
848 |
|
849 |
|
850 /** |
|
851 Formats and appends text onto the end of this descriptor's data. |
|
852 |
|
853 The length of this descriptor is incremented to reflect the new content. |
|
854 |
|
855 The behaviour of this function is the same as |
|
856 AppendFormat(TRefByValue<const TDesC16> aFmt,TDes16Overflow *aOverflowHandler,...). |
|
857 In practice, it is better and easier to use AppendFormat(), passing a variable number of |
|
858 arguments as required by the format string. |
|
859 |
|
860 @param aFormat The descriptor containing the format string. |
|
861 @param aList A pointer to an argument list. |
|
862 @param aOverflowHandler If supplied, a pointer to the overflow handler. |
|
863 |
|
864 @see TDes16::AppendFormat |
|
865 @see VA_LIST |
|
866 */ |
|
867 EXPORT_C void TDes16::AppendFormatList(const TDesC16 &aFormat,VA_LIST aList,TDes16Overflow *aOverflowHandler) |
|
868 { |
|
869 |
|
870 DoAppendFormatList<TDes16, TDes16Overflow, TDesC16, TFormatedText16, TLex16, TPanicker16, sizeof(TUint16)>(*this,aFormat,aList,aOverflowHandler); |
|
871 } |
|
872 |