wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * FormatCmd.java
3 *
4 * Copyright (c) 1997 Sun Microsystems, Inc.
5 *
6 * See the file "license.terms" for information on usage and
7 * redistribution of this file, and for a DISCLAIMER OF ALL
8 * WARRANTIES.
9 *
10 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
11 *
12 * RCS @(#) $Id: FormatCmd.java,v 1.7 2003/02/01 00:56:29 mdejong Exp $
13 *
14 */
15 using System;
16 using System.Text;
17 namespace tcl.lang
18 {
19  
20 /// <summary> This class implements the built-in "format" command in Tcl.</summary>
21  
22 class FormatCmd : Command
23 {
24  
25 private const int LEFT_JUSTIFY = 1;
26 private const int SHOW_SIGN = 2;
27 private const int SPACE_OR_SIGN = 4;
28 private const int PAD_W_ZERO = 8;
29 private const int ALT_OUTPUT = 16;
30 private const int SIGNED_VALUE = 32;
31 private const int RADIX = 1; // Integer types. %d, %x, %o
32 private const int FLOAT = 2; // Floating point. %f
33 private const int EXP = 3; // Exponentional. %e and %E
34 private const int GENERIC = 4; // Floating or exponential,
35 // depending on exponent. %g
36  
37 /// <summary> This procedure is invoked to process the "format" Tcl command.
38 /// See the user documentation for details on what it does.
39 ///
40 /// The first argument to the cmdProc is the formatString. The cmdProc
41 /// simply copies all the chars into the sbuf until a '%' is found. At
42 /// this point the cmdProc parces the formatString and determines the
43 /// format parameters. The parcing of the formatString can be broken into
44 /// six possible phases:
45 ///
46 /// Phase 0 - Simply Print: If the next char is %
47 /// Phase 1 - XPG3 Position Specifier: If the format [1-n]$ is used
48 /// Phase 2 - A Set of Flags: One or more of the following + -
49 /// [space] 0 #
50 /// Phase 3 - A Minimun Field Width Either [integer] or *
51 /// Phase 4 - A Precision If the format .[integer] or .*
52 /// Phase 5 - A Length Modifier If h is present
53 /// Phase 6 - A Conversion Character If one of the following is used
54 /// d u i o x X c s f E g G
55 ///
56 /// Any phase can skip ahead one or more phases, but are not allowed
57 /// to move back to previous phases. Once the parameters are determined
58 /// the cmdProc calls one of three private methods that returns a fully
59 /// formatted string. This loop occurs for ever '%' in the formatString.
60 /// </summary>
61  
62 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
63 {
64  
65  
66 StringBuilder sbuf; // Stores the return value of the parsed
67 // format string
68 StrtoulResult stoul; // A return object to the strtoul call
69 char[] format; // The format argument is converted to a char
70 // array and manipulated as such
71 int phase; // Stores the current phase of the parsing
72 int width; // Minimum field width
73 int precision; // Field precision from field specifier
74 int fmtFlags; // Used to store the format flags ( #,+,etc)
75 int argIndex; // Index of argument to substitute next.
76 int fmtIndex; // Used to locate end of the format fields.
77 int endIndex; // Used to locate end of numerical fields.
78 int intValue; // Generic storage variable
79 long lngValue; // Store the TclInteger.get() result
80 double dblValue; // Store the TclDouble.get() result
81 bool noPercent; // Special case for speed: indicates there's
82 // no field specifier, just a string to copy.
83 bool xpgSet; // Indicates that xpg has been used for the
84 // particular format of the main while loop
85 bool gotXpg; // True means that an XPG3 %n$-style
86 // specifier has been seen.
87 bool gotSequential; // True means that a regular sequential
88 // (non-XPG3) conversion specifier has
89 // been seen.
90 bool useShort; // Value to be printed is short
91 // (half word).
92 bool precisionSet; // Used for f, e, and E conversions
93 bool cont; // Used for phase 3
94  
95 if ( argv.Length < 2 )
96 {
97 throw new TclNumArgsException( interp, 1, argv, "formatString ?arg arg ...?" );
98 }
99  
100 argIndex = 2;
101 fmtIndex = 0;
102 gotXpg = gotSequential = false;
103  
104 format = argv[1].ToString().ToCharArray();
105 sbuf = new StringBuilder();
106  
107 // So, what happens here is to scan the format string one % group
108 // at a time, making many individual appends to the StringBuffer.
109  
110 while ( fmtIndex < format.Length )
111 {
112 fmtFlags = phase = width = 0;
113 noPercent = true;
114 xpgSet = precisionSet = useShort = false;
115 precision = -1;
116  
117 // Append all characters to sbuf that are not used for the
118 // format specifier.
119  
120  
121 if ( format[fmtIndex] != '%' )
122 {
123 int i;
124 for ( i = fmtIndex; ( i < format.Length ); i++ )
125 {
126 if ( format[i] == '%' )
127 {
128 noPercent = false;
129 break;
130 }
131 }
132 sbuf.Append( new string( format, fmtIndex, i - fmtIndex ) );
133 fmtIndex = i;
134 if ( noPercent )
135 {
136 break;
137 }
138 }
139  
140 // If true, then a % has been indicated but we are at the end
141 // of the format string. Call function to throw exception.
142  
143 if ( fmtIndex + 1 >= format.Length )
144 {
145 errorEndMiddle( interp );
146 }
147  
148 // Phase 0:
149 // Check for %%. If true then simply write a single '%'
150 // to the list.
151  
152 checkOverFlow( interp, format, fmtIndex + 1 );
153 if ( format[fmtIndex + 1] == '%' )
154 {
155 sbuf.Append( "%" );
156 fmtIndex += 2;
157 // Re-enter the loop
158  
159 continue;
160 }
161  
162 fmtIndex++;
163 checkOverFlow( interp, format, fmtIndex );
164 if ( System.Char.IsDigit( format[fmtIndex] ) )
165 {
166 // Parce the format array looking for the end of
167 // the number.
168  
169 stoul = strtoul( format, fmtIndex );
170 intValue = (int)stoul.value;
171 endIndex = stoul.index;
172  
173 if ( format[endIndex] == '$' )
174 {
175 if ( intValue == 0 )
176 {
177 errorBadIndex( interp, true );
178 }
179  
180 // Phase 1:
181 // Check for an XPG3-style %n$ specification.
182 // Note: there must not be a mixture of XPG3
183 // specs and non-XPG3 specs in the same format string.
184  
185 if ( gotSequential )
186 {
187 errorMixedXPG( interp );
188 }
189 gotXpg = true;
190 xpgSet = true;
191 phase = 2;
192 fmtIndex = endIndex + 1;
193 argIndex = intValue + 1;
194 if ( ( argIndex < 2 ) || ( argIndex >= argv.Length ) )
195 {
196 errorBadIndex( interp, gotXpg );
197 }
198 }
199 else
200 {
201 // Phase 3:
202 // Format jumped straight to phase 3; Setting
203 // width field. Again, verify that all format
204 // specifiers are sequential.
205  
206 if ( gotXpg )
207 {
208 errorMixedXPG( interp );
209 }
210 gotSequential = true;
211 if ( format[fmtIndex] != '0' )
212 {
213 fmtIndex = endIndex;
214 width = intValue;
215 phase = 4;
216 }
217 }
218 }
219 else
220 {
221 if ( gotXpg )
222 {
223 errorMixedXPG( interp );
224 }
225 gotSequential = true;
226 }
227  
228 // Phase 2:
229 // Setting the Format Flags. At this point the phase value
230 // can be either zero or three. Anything greater is an
231 // incorrect format.
232  
233 if ( phase < 3 )
234 {
235 checkOverFlow( interp, format, fmtIndex );
236 char ch = format[fmtIndex];
237 cont = true;
238 while ( cont )
239 {
240 switch ( ch )
241 {
242  
243 case '-':
244 {
245 fmtFlags |= LEFT_JUSTIFY;
246 break;
247 }
248  
249 case '#':
250 {
251 fmtFlags |= ALT_OUTPUT;
252 break;
253 }
254  
255 case '0':
256 {
257 fmtFlags |= PAD_W_ZERO;
258 break;
259 }
260  
261 case ' ':
262 {
263 fmtFlags |= SPACE_OR_SIGN;
264 break;
265 }
266  
267 case '+':
268 {
269 fmtFlags |= SHOW_SIGN;
270 break;
271 }
272  
273 default:
274 {
275 cont = false;
276 }
277 break;
278  
279 }
280 if ( cont )
281 {
282 fmtIndex++;
283 checkOverFlow( interp, format, fmtIndex );
284 ch = format[fmtIndex];
285 }
286 }
287 phase = 3;
288 }
289  
290 // Phase 3:
291 // Setting width field. Partially redundant code from the
292 // Phase 1 if/else statement, but this is made to run fast.
293  
294 checkOverFlow( interp, format, fmtIndex );
295 if ( System.Char.IsDigit( format[fmtIndex] ) )
296 {
297 stoul = strtoul( format, fmtIndex );
298 width = (int)stoul.value;
299 fmtIndex = stoul.index;
300 }
301 else if ( format[fmtIndex] == '*' )
302 {
303 if ( argv.Length > argIndex )
304 {
305 width = TclInteger.get( interp, argv[argIndex] );
306 if ( width < 0 )
307 {
308 width = -width;
309 fmtFlags |= LEFT_JUSTIFY;
310 }
311 argIndex++;
312 fmtIndex++;
313 }
314 }
315  
316 // Phase 4:
317 // Setting the precision field.
318  
319 checkOverFlow( interp, format, fmtIndex );
320 if ( format[fmtIndex] == '.' )
321 {
322 fmtIndex++;
323 checkOverFlow( interp, format, fmtIndex );
324 if ( System.Char.IsDigit( format[fmtIndex] ) )
325 {
326 precisionSet = true;
327  
328 stoul = strtoul( format, fmtIndex );
329 precision = (int)stoul.value;
330 fmtIndex = stoul.index;
331 }
332 else if ( format[fmtIndex] == '*' )
333 {
334 if ( argv.Length > argIndex )
335 {
336 precisionSet = true;
337 precision = TclInteger.get( interp, argv[argIndex] );
338 argIndex++;
339 fmtIndex++;
340 checkOverFlow( interp, format, fmtIndex );
341 }
342 }
343 else
344 {
345 // Format field had a '.' without an integer or '*'
346 // preceeding it (eg %2.d or %2.-5d)
347  
348 errorBadField( interp, format[fmtIndex] );
349 }
350 }
351  
352 // Phase 5:
353 // Setting the length modifier.
354  
355 if ( format[fmtIndex] == 'h' )
356 {
357 fmtIndex++;
358 checkOverFlow( interp, format, fmtIndex );
359 useShort = true;
360 }
361 else if ( format[fmtIndex] == 'l' )
362 {
363 fmtIndex++;
364 checkOverFlow( interp, format, fmtIndex );
365  
366 // 'l' is ignored, but should still be processed.
367 }
368  
369 if ( ( argIndex < 2 ) || ( argIndex >= argv.Length ) )
370 {
371 errorBadIndex( interp, gotXpg );
372 }
373  
374 // Phase 6:
375 // Setting conversion field.
376 // At this point, variables are initialized as follows:
377 //
378 // width The specified field width. This is always
379 // non-negative. Zero is the default.
380 // precision The specified precision. The default
381 // is -1.
382 // argIndex The argument index from the argv array
383 // for the appropriate arg.
384 // fmtFlags The format flags are set via bitwise
385 // operations. Below are the bits
386 // and their meanings.
387  
388 // ALT_OUTPUT set if a '#' is present.
389 // SHOW_SIGN set if a '+' is present.
390 // SPACE_OR_SIGN set if a ' ' is present.
391 // LEFT_JUSTIFY set if a '-' is present or if the
392 // field width was negative.
393 // PAD_W_ZERO set if a '0' is present
394  
395 string strValue = "";
396 char index = format[fmtIndex];
397  
398 switch ( index )
399 {
400  
401 case 'u':
402 case 'd':
403 case 'o':
404 case 'x':
405 case 'X':
406 case 'i':
407 {
408 if ( index == 'u' )
409 {
410 // Since Java does not provide unsigned ints we need to
411 // make our own. If the value is negative we need to
412 // clear out all of the leading bits from the 33rd bit
413 // and on. The result is a long value equal to that
414 // of an unsigned int.
415  
416 lngValue = (long)TclInteger.get( interp, argv[argIndex] );
417 if ( lngValue < 0 )
418 {
419 lngValue = ( lngValue << 32 );
420 lngValue = ( SupportClass.URShift( lngValue, 32 ) );
421 }
422 }
423 else
424 {
425 fmtFlags |= SIGNED_VALUE;
426 lngValue = (long)TclInteger.get( interp, argv[argIndex] );
427 }
428  
429 // If the useShort option has been selected, we need
430 // to clear all but the first 16 bits.
431  
432 if ( useShort )
433 {
434 lngValue = ( lngValue << 48 );
435 lngValue = ( lngValue >> 48 );
436 }
437  
438 if ( index == 'o' )
439 {
440 sbuf.Append( cvtLngToStr( lngValue, width, precision, fmtFlags, 8, "01234567".ToCharArray(), "0" ) );
441 }
442 else if ( index == 'x' )
443 {
444 sbuf.Append( cvtLngToStr( lngValue, width, precision, fmtFlags, 16, "0123456789abcdef".ToCharArray(), "0x" ) );
445 }
446 else if ( index == 'X' )
447 {
448 sbuf.Append( cvtLngToStr( lngValue, width, precision, fmtFlags, 16, "0123456789ABCDEF".ToCharArray(), "0X" ) );
449 }
450 else
451 {
452 sbuf.Append( cvtLngToStr( lngValue, width, precision, fmtFlags, 10, "0123456789".ToCharArray(), "" ) );
453 }
454 break;
455 }
456  
457 case 'c':
458 {
459 intValue = 0;
460 char[] arr = new char[] { (char)TclInteger.get( interp, argv[argIndex] ) };
461 strValue = new string( arr );
462 sbuf.Append( cvtStrToStr( strValue, width, precision, fmtFlags ) );
463 break;
464 }
465  
466 case 's':
467 {
468  
469 strValue = argv[argIndex].ToString();
470 sbuf.Append( cvtStrToStr( strValue, width, precision, fmtFlags ) );
471 break;
472 }
473  
474 case 'f':
475 {
476 dblValue = TclDouble.get( interp, argv[argIndex] );
477 sbuf.Append( cvtDblToStr( dblValue, width, precision, fmtFlags, 10, "0123456789".ToCharArray(), "", FLOAT ) );
478 break;
479 }
480  
481 case 'e':
482 {
483 dblValue = TclDouble.get( interp, argv[argIndex] );
484 sbuf.Append( cvtDblToStr( dblValue, width, precision, fmtFlags, 10, "e".ToCharArray(), "", EXP ) );
485 break;
486 }
487  
488 case 'E':
489 {
490 dblValue = TclDouble.get( interp, argv[argIndex] );
491 sbuf.Append( cvtDblToStr( dblValue, width, precision, fmtFlags, 10, "E".ToCharArray(), "", EXP ) );
492 break;
493 }
494  
495 case 'g':
496 {
497 dblValue = TclDouble.get( interp, argv[argIndex] );
498 sbuf.Append( cvtDblToStr( dblValue, width, precision, fmtFlags, 10, "e".ToCharArray(), "", GENERIC ) );
499 break;
500 }
501  
502 case 'G':
503 {
504 dblValue = TclDouble.get( interp, argv[argIndex] );
505 sbuf.Append( cvtDblToStr( dblValue, width, precision, fmtFlags, 10, "E".ToCharArray(), "", GENERIC ) );
506 break;
507 }
508  
509 default:
510 {
511 errorBadField( interp, format[fmtIndex] );
512 }
513 break;
514  
515 }
516 fmtIndex++;
517 argIndex++;
518 }
519 interp.setResult( sbuf.ToString() );
520 return TCL.CompletionCode.RETURN;
521 }
522  
523  
524 /// <summary> This procedure is invoked in "phase 6" od the Format cmdProc. It
525 /// converts the lngValue to a string with a specified format determined by
526 /// the other input variables.
527 /// </summary>
528 /// <param name="lngValue"> - Is the value of the argument input
529 /// </param>
530 /// <param name="width"> - The minimum width of the string.
531 /// </param>
532 /// <param name="precision">- The minimum width if the integer. If the string len
533 /// is less than precision, leading 0 are appended.
534 /// </param>
535 /// <param name="flags"> - Specifies various formatting to the string
536 /// representation (-, +, space, 0, #)
537 /// </param>
538 /// <param name="base"> - The base of the integer (8, 10, 16)
539 /// </param>
540 /// <param name="charSet"> - The char set to use for the conversion to ascii OR
541 /// The char used for sci notation.
542 /// </param>
543 /// <param name="altPrefix">- If not empty, str to append on the beginnig of the
544 /// resulting string (eg 0 or 0x or 0X ).
545 /// </param>
546 /// <returns> String representation of the long.
547 /// </returns>
548  
549 private string cvtLngToStr( long lngValue, int width, int precision, int flags, int base_, char[] charSet, string altPrefix )
550 {
551 StringBuilder sbuf = new StringBuilder( 100 );
552 StringBuilder tmpBuf = new StringBuilder( 0 ).Append( "" );
553  
554 int i;
555 int length;
556 int nspace;
557 int prefixSize = 0;
558 char prefix = (char)( 0 );
559  
560 // For the format %#x, the value zero is printed "0" not "0x0".
561 // I think this is stupid.
562  
563 if ( lngValue == 0 )
564 {
565 flags = ( flags | ALT_OUTPUT );
566 }
567  
568  
569 if ( ( flags & SIGNED_VALUE ) != 0 )
570 {
571 if ( lngValue < 0 )
572 {
573 if ( altPrefix.Length > 0 )
574 {
575 lngValue = ( lngValue << 32 );
576 lngValue = ( SupportClass.URShift( lngValue, 32 ) );
577 }
578 else
579 {
580 lngValue = -lngValue;
581 prefix = '-';
582 prefixSize = 1;
583 }
584 }
585 else if ( ( flags & SHOW_SIGN ) != 0 )
586 {
587 prefix = '+';
588 prefixSize = 1;
589 }
590 else if ( ( flags & SPACE_OR_SIGN ) != 0 )
591 {
592 prefix = ' ';
593 prefixSize = 1;
594 }
595 }
596  
597 if ( ( ( PAD_W_ZERO & flags ) != 0 ) && ( precision < width - prefixSize ) )
598 {
599 precision = width - prefixSize;
600 }
601  
602 // Convert to ascii
603  
604 do
605 {
606 sbuf.Insert( 0, charSet[(int)( lngValue % base_ )] );
607 lngValue = lngValue / base_;
608 }
609 while ( lngValue > 0 );
610  
611 length = sbuf.Length;
612 for ( i = ( precision - length ); i > 0; i-- )
613 {
614 sbuf.Insert( 0, '0' );
615 }
616 if ( prefix != 0 )
617 {
618 sbuf.Insert( 0, prefix );
619 }
620 if ( ( flags & ALT_OUTPUT ) != 0 )
621 {
622 if ( ( altPrefix.Length > 0 ) && ( sbuf[0] != altPrefix[0] ) )
623 {
624 sbuf.Insert( 0, altPrefix );
625 }
626 }
627  
628 // The text of the conversion is pointed to by "bufpt" and is
629 // "length" characters long. The field width is "width". Do
630 // the output.
631  
632 nspace = width - sbuf.Length;
633 if ( nspace > 0 )
634 {
635 tmpBuf = new StringBuilder( nspace );
636 for ( i = 0; i < nspace; i++ )
637 {
638 tmpBuf.Append( " " );
639 }
640 }
641  
642 if ( ( LEFT_JUSTIFY & flags ) != 0 )
643 {
644 // left justified
645  
646 return sbuf.ToString() + tmpBuf.ToString();
647 }
648 else
649 {
650 // right justified
651  
652 return tmpBuf.ToString() + sbuf.ToString();
653 }
654 }
655  
656 internal static string toString( double dblValue, int precision, int base_ )
657 {
658 return cvtDblToStr( dblValue, 0, precision, 0, base_, "e".ToCharArray(), null, GENERIC );
659 }
660  
661 /// <summary> This procedure is invoked in "phase 6" od the Format cmdProc. It
662 /// converts the lngValue to a string with a specified format determined
663 /// by the other input variables.
664 /// </summary>
665 /// <param name="dblValue"> - Is the value of the argument input
666 /// </param>
667 /// <param name="width"> - The minimum width of the string.
668 /// </param>
669 /// <param name="precision">- The minimum width if the integer. If the string len
670 /// is less than precision, leading 0 are appended.
671 /// </param>
672 /// <param name="flags"> - Specifies various formatting to the string
673 /// representation (-, +, space, 0, #)
674 /// </param>
675 /// <param name="base"> - The base of the integer (8, 10, 16)
676 /// </param>
677 /// <param name="charSet"> - The char set to use for the conversion to ascii OR
678 /// The char used for sci notation.
679 /// </param>
680 /// <param name="altPrefix">- If not empty, str to append on the beginnig of the
681 /// resulting string (eg 0 or 0x or 0X ).
682 /// </param>
683 /// <param name="xtype"> - Either FLOAT, EXP, or GENERIC depending on the
684 /// format specifier.
685 /// </param>
686 /// <returns> String representation of the long.
687 /// </returns>
688  
689 private static string cvtDblToStr( double dblValue, int width, int precision, int flags, int base_, char[] charSet, string altPrefix, int xtype )
690 {
691 if ( base_ == 10 )
692 return dblValue.ToString();
693 StringBuilder sbuf = new StringBuilder( 100 );
694 int i;
695 int exp;
696 int length;
697 int count;
698 int digit;
699 int prefixSize = 0;
700 char prefix = (char)( 0 );
701 double rounder;
702 bool flag_exp = false; // Flag for exponential representation
703 bool flag_rtz = true; // Flag for "remove trailing zeros"
704 bool flag_dp = true; // Flag for remove "decimal point"
705  
706 if ( System.Double.IsNaN( dblValue ) )
707 {
708 return "NaN";
709 }
710 if ( dblValue == System.Double.NegativeInfinity )
711 {
712 return "-Inf";
713 }
714 if ( dblValue == System.Double.PositiveInfinity )
715 {
716 return "Inf";
717 }
718  
719 // If precision < 0 (eg -1) then the precision defaults
720  
721 if ( precision < 0 )
722 {
723 precision = 6;
724 }
725  
726 if ( dblValue < 0.0 )
727 {
728 dblValue = -dblValue;
729 prefix = '-';
730 prefixSize = 1;
731 }
732 // ATK I do not know how C# can note negative 0
733 // else if (dblValue == 0.0 && (dblValue).Equals((- 0.0)))
734 // {
735 // // Handle -0.0
736 // //
737 // // 15.19.1 "Numerical Comparison Operators <, <=, >, and >= "
738 // // of the Java Language Spec says:
739 // // "Positive zero and negative zero are considered
740 // // equal. Therefore, -0.0<0.0 is false, for example, but
741 // // -0.0<=0.0 is true."
742 // //
743 // // The Double.equal man page says:
744 // // "If d1 represents +0.0 while d2 represents -0.0, or
745 // // vice versa, the equal test has the value false, even
746 // // though +0.0==-0.0 has the value true. This allows
747 // // hashtables to operate properly.
748 //
749 // dblValue = - dblValue;
750 // prefix = '-';
751 // prefixSize = 1;
752 // }
753 else if ( ( flags & SHOW_SIGN ) != 0 )
754 {
755 prefix = '+';
756 prefixSize = 1;
757 }
758 else if ( ( flags & SPACE_OR_SIGN ) != 0 )
759 {
760 prefix = ' ';
761 prefixSize = 1;
762 }
763  
764 // For GENERIC xtypes the precision includes the ones digit
765 // so just decrement to get the correct precision.
766  
767 if ( xtype == GENERIC && precision > 0 )
768 {
769 precision--;
770 }
771  
772 // Rounding works like BSD when the constant 0.4999 is used. Wierd!
773 //for (i = precision, rounder = 0.4999; i > 0; i--, rounder *= 0.1)
774 //;
775 string ss = "0." + new String( '0', precision ) + "4999";
776 rounder = Convert.ToDouble( ss );
777 if ( xtype == FLOAT )
778 {
779 dblValue += rounder;
780 }
781  
782 // Normalize dblValue to within 10.0 > dblValue >= 1.0
783  
784 exp = 0;
785 if ( dblValue > 0.0 )
786 {
787 int k = 0;
788 while ( ( dblValue >= 1e8 ) && ( k++ < 100 ) )
789 {
790 dblValue *= 1e-8;
791 exp += 8;
792 }
793 while ( ( dblValue >= 10.0 ) && ( k++ < 100 ) )
794 {
795 dblValue *= 0.1;
796 exp++;
797 }
798 while ( ( dblValue < 1e-8 ) && ( k++ < 100 ) )
799 {
800 dblValue *= 1e8;
801 exp -= 8;
802 }
803 while ( ( dblValue < 1.0 ) && ( k++ < 100 ) )
804 {
805 dblValue *= 10.0;
806 exp--;
807 }
808 if ( k >= 100 )
809 {
810 return "NaN";
811 }
812 }
813  
814 // If the field type is GENERIC, then convert to either EXP
815 // or FLOAT, as appropriate.
816  
817 flag_exp = xtype == EXP;
818 if ( xtype != FLOAT )
819 {
820 //dblValue += rounder;
821 if ( dblValue >= 10.0 )
822 {
823 dblValue *= 0.1;
824 exp++;
825 }
826 }
827 if ( xtype == GENERIC )
828 {
829 flag_rtz = !( ( flags & ALT_OUTPUT ) != 0 );
830 if ( ( exp < -4 ) || ( exp > precision ) )
831 {
832 xtype = EXP;
833 }
834 else
835 {
836 precision = ( precision - exp );
837 xtype = FLOAT;
838 }
839 }
840 else
841 {
842 flag_rtz = false;
843 }
844  
845 // The "exp+precision" test causes output to be of type EXP if
846 // the precision is too large to fit in buf[].
847  
848 count = 0;
849 if ( xtype == FLOAT )
850 {
851 flag_dp = ( ( precision > 0 ) || ( ( flags & ALT_OUTPUT ) != 0 ) );
852 if ( prefixSize > 0 )
853 {
854 // Sign
855  
856 sbuf.Append( prefix );
857 }
858 if ( exp < 0 )
859 {
860 // Digits before "."
861  
862 sbuf.Append( '0' );
863 }
864 for ( ; exp >= 0; exp-- )
865 {
866 if ( count++ >= 16 )
867 {
868 sbuf.Append( '0' );
869 }
870 else
871 {
872  
873 digit = (int)dblValue;
874 dblValue = ( dblValue - digit ) * 10.0;
875 sbuf.Append( digit );
876 }
877 }
878 if ( flag_dp )
879 {
880 sbuf.Append( '.' );
881 }
882 for ( exp++; ( exp < 0 ) && ( precision > 0 ); precision--, exp++ )
883 {
884 sbuf.Append( '0' );
885 }
886 while ( ( precision-- ) > 0 )
887 {
888 if ( count++ >= 16 )
889 {
890 sbuf.Append( '0' );
891 }
892 else
893 {
894  
895 digit = (int)dblValue;
896 dblValue = ( dblValue - digit ) * 10.0;
897 sbuf.Append( digit );
898 }
899 }
900  
901 if ( flag_rtz && flag_dp )
902 {
903 // Remove trailing zeros and "."
904  
905 int len, index;
906 len = index = 0;
907 for ( len = ( sbuf.Length - 1 ), index = 0; ( len >= 0 ) && ( sbuf[len] == '0' ); len--, index++ )
908 ;
909  
910 if ( ( len >= 0 ) && ( sbuf[len] == '.' ) )
911 {
912 index++;
913 }
914  
915 if ( index > 0 )
916 {
917 sbuf = new StringBuilder( sbuf.ToString().Substring( 0, ( sbuf.Length - index ) - ( 0 ) ) );
918 }
919 }
920 }
921 else
922 {
923 // EXP or GENERIC
924  
925 flag_dp = ( ( precision > 0 ) || ( ( flags & ALT_OUTPUT ) != 0 ) );
926  
927 if ( prefixSize > 0 )
928 {
929 sbuf.Append( prefix );
930 }
931  
932 digit = (int)dblValue;
933 dblValue = ( dblValue - digit ) * 10.0;
934 sbuf.Append( digit );
935 if ( flag_dp )
936 {
937 sbuf.Append( '.' );
938 }
939 while ( precision-- > 0 )
940 {
941 if ( count++ >= 16 )
942 {
943 sbuf.Append( '0' );
944 }
945 else
946 {
947  
948 digit = (int)dblValue;
949 dblValue = ( dblValue - digit ) * 10.0;
950 sbuf.Append( digit );
951 }
952 }
953  
954 if ( flag_rtz && flag_dp )
955 {
956 // Remove trailing zeros and "."
957  
958 for ( i = 0, length = ( sbuf.Length - 1 ); ( length >= 0 ) && ( sbuf[length] == '0' ); length--, i++ )
959 ;
960  
961 if ( ( length >= 0 ) && ( sbuf[length] == '.' ) )
962 {
963 i++;
964 }
965  
966 if ( i > 0 )
967 {
968 sbuf = new StringBuilder( sbuf.ToString().Substring( 0, ( sbuf.Length - i ) - ( 0 ) ) );
969 }
970 }
971 if ( ( exp != 0 ) || flag_exp )
972 {
973 sbuf.Append( charSet[0] );
974 if ( exp < 0 )
975 {
976 sbuf.Append( '-' );
977 exp = -exp;
978 }
979 else
980 {
981 sbuf.Append( '+' );
982 }
983 if ( exp >= 100 )
984 {
985 sbuf.Append( ( exp / 100 ) );
986 exp %= 100;
987 }
988 sbuf.Append( exp / 10 );
989 sbuf.Append( exp % 10 );
990 }
991 }
992  
993 // The converted number is in sbuf. Output it.
994 // Note that the number is in the usual order, not reversed as with
995 // integer conversions.
996  
997 length = sbuf.Length;
998  
999 // Special case: Add leading zeros if the PAD_W_ZERO flag is
1000 // set and we are not left justified
1001  
1002 if ( ( ( PAD_W_ZERO & flags ) != 0 ) && ( ( LEFT_JUSTIFY & flags ) == 0 ) )
1003 {
1004 int nPad = width - length;
1005 i = prefixSize;
1006 while ( ( nPad-- ) > 0 )
1007 {
1008 sbuf.Insert( prefixSize, '0' );
1009 }
1010 length = width;
1011 }
1012  
1013 // Count the number of spaces remaining and creat a StringBuffer
1014 // (tmpBuf) with the correct number of spaces.
1015  
1016 int nspace = width - length;
1017 StringBuilder tmpBuf = new StringBuilder( 0 ).Append( "" );
1018 if ( nspace > 0 )
1019 {
1020 tmpBuf = new StringBuilder( nspace );
1021 for ( i = 0; i < nspace; i++ )
1022 {
1023 tmpBuf.Append( " " );
1024 }
1025 }
1026  
1027 if ( ( LEFT_JUSTIFY & flags ) != 0 )
1028 {
1029 // left justified
1030  
1031 return sbuf.ToString() + tmpBuf.ToString();
1032 }
1033 else
1034 {
1035 // right justified
1036  
1037 return tmpBuf.ToString() + sbuf.ToString();
1038 }
1039 }
1040  
1041 /// <summary> This procedure is invoked in "phase 6" od the Format cmdProc. It
1042 /// converts the strValue to a string with a specified format determined
1043 /// by the other input variables.
1044 /// </summary>
1045 /// <param name="strValue"> - Is the String w/o formatting.
1046 /// </param>
1047 /// <param name="width"> - The minimum width of the string.
1048 /// </param>
1049 /// <param name="precision">- The minimum width if the integer. If the string
1050 /// len is less than precision, leading 0 are
1051 /// appended.
1052 /// </param>
1053 /// <param name="flags"> - Specifies various formatting to the string
1054 /// representation (-, +, space, 0, #)
1055 /// </param>
1056 /// <returns> String representation of the integer.
1057 /// </returns>
1058  
1059 private static string cvtStrToStr( string strValue, int width, int precision, int flags )
1060 {
1061 string left = "";
1062 string right = "";
1063  
1064 if ( precision < 0 )
1065 {
1066 precision = 0;
1067 }
1068  
1069 if ( ( precision != 0 ) && ( precision < strValue.Length ) )
1070 {
1071 strValue = strValue.Substring( 0, ( precision ) - ( 0 ) );
1072 }
1073  
1074 if ( width > strValue.Length )
1075 {
1076 StringBuilder sbuf = new StringBuilder();
1077 int index = ( width - strValue.Length );
1078 for ( int i = 0; i < index; i++ )
1079 {
1080 if ( ( flags & PAD_W_ZERO ) != 0 )
1081 {
1082 sbuf.Append( '0' );
1083 }
1084 else
1085 {
1086 sbuf.Append( ' ' );
1087 }
1088 }
1089 if ( ( LEFT_JUSTIFY & flags ) != 0 )
1090 {
1091 right = sbuf.ToString();
1092 }
1093 else
1094 {
1095 left = sbuf.ToString();
1096 }
1097 }
1098  
1099 return ( left + strValue + right );
1100 }
1101  
1102  
1103 /// <summary> Search through the array while the current char is a digit. When end
1104 /// of array occurs or the char is not a digit, stop the loop, convert the
1105 /// sub-array into a long. At this point return a StrtoulResult object
1106 /// that contains the new long value and the current pointer to the array.
1107 ///
1108 /// </summary>
1109 /// <param name="arr">- the array that contains a string representation of an int.
1110 /// </param>
1111 /// <param name="endIndex">- the arr index where the numeric value begins.
1112 /// </param>
1113 /// <returns> StrtoResult containing the value and new index/
1114 /// </returns>
1115  
1116 private StrtoulResult strtoul( char[] arr, int endIndex )
1117 {
1118 int orgIndex;
1119  
1120 orgIndex = endIndex;
1121 for ( ; endIndex < arr.Length; endIndex++ )
1122 {
1123 if ( !System.Char.IsDigit( arr[endIndex] ) )
1124 {
1125 break;
1126 }
1127 }
1128 return ( new StrtoulResult( System.Int64.Parse( new string( arr, orgIndex, endIndex - orgIndex ) ), endIndex, 0 ) );
1129 }
1130  
1131  
1132 /*
1133 *
1134 * Error routines:
1135 *
1136 */
1137  
1138  
1139 /// <summary> Called whenever the fmtIndex in the cmdProc is changed. It verifies
1140 /// the the array index is still within the bounds of the array. If no
1141 /// throw error.
1142 /// </summary>
1143 /// <param name="interp"> - The TclInterp which called the cmdProc method .
1144 /// </param>
1145 /// <param name="arr"> - The array to be checked.
1146 /// </param>
1147 /// <param name="index"> - The new value for the array index.
1148 /// </param>
1149  
1150 private static void checkOverFlow( Interp interp, char[] arr, int index )
1151 {
1152 if ( ( index >= arr.Length ) || ( index < 0 ) )
1153 {
1154 throw new TclException( interp, "\"%n$\" argument index out of range" );
1155 }
1156 }
1157  
1158  
1159 /// <summary> Called whenever Sequential format specifiers are interlaced with
1160 /// XPG format specifiers in one call to cmdProc.
1161 ///
1162 /// </summary>
1163 /// <param name="interp"> - The TclInterp which called the cmdProc method .
1164 /// </param>
1165  
1166 private static void errorMixedXPG( Interp interp )
1167 {
1168 throw new TclException( interp, "cannot mix \"%\" and \"%n$\" conversion specifiers" );
1169 }
1170  
1171  
1172 /// <summary> Called whenever the argIndex access outside the argv array. If the
1173 /// type is an XPG then the error message is different.
1174 ///
1175 /// </summary>
1176 /// <param name="interp"> - The TclInterp which called the cmdProc method .
1177 /// </param>
1178 /// <param name="gotXpg"> - Boolean the determines if the current format is of a
1179 /// XPG type or Sequential
1180 /// </param>
1181  
1182 private static void errorBadIndex( Interp interp, bool gotXpg )
1183 {
1184 if ( gotXpg )
1185 {
1186 throw new TclException( interp, "\"%n$\" argument index out of range" );
1187 }
1188 else
1189 {
1190 throw new TclException( interp, "not enough arguments for all format specifiers" );
1191 }
1192 }
1193  
1194  
1195 /// <summary> Called whenever the current char in the format array is erroneous
1196 ///
1197 /// </summary>
1198 /// <param name="interp"> - The TclInterp which called the cmdProc method .
1199 /// </param>
1200 /// <param name="fieldSpecifier"> - The erroneous character
1201 /// </param>
1202  
1203 private static void errorBadField( Interp interp, char fieldSpecifier )
1204 {
1205 throw new TclException( interp, "bad field specifier \"" + fieldSpecifier + "\"" );
1206 }
1207  
1208  
1209 /// <summary> Called whenever the a '%' is found but then the format string ends.
1210 ///
1211 /// </summary>
1212 /// <param name="interp"> - The TclInterp which called the cmdProc method .
1213 /// </param>
1214  
1215 private static void errorEndMiddle( Interp interp )
1216 {
1217 throw new TclException( interp, "format string ended in middle of field specifier" );
1218 }
1219 }
1220 }