2002-06-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / corlib / System / IntegerFormatter.cs
1 //
2 // System.IntegerFormatter.cs
3 //
4 // Author:
5 //   Derek Holden  (dholden@draper.com)
6 //
7 // (C) Derek Holden  dholden@draper.com
8 //
9
10 //
11 // Format integer types. Completely based off ECMA docs
12 // for IFormattable specification. Has been tested w/ 
13 // all integral types, from boundry to boundry, w/ all 
14 // formats A## ("G", "G0" ... "G99", "P", "P0" ... "P99").
15 //
16 // If you make any changes, please make sure to check the
17 // boundry format precisions (0, 99) and the min / max values
18 // of the data types (Int32.[Max/Min]Value).
19 //
20 // Using int as an example, it is currently set up as
21 //
22 // Int32 {
23 //   int value;
24 //   public string ToString (string format, NumberFormatInfo nfi) {
25 //      return IntegerFormatter.NumberToString (format, nfi, value);
26 //   }
27 //
28 // IntegerFormatter {
29 //   public string NumberToString (string format, NumberFormatInfo nfi, int value) {
30 //      ParseFormat (format);
31 //      switch (format type) {
32 //        case 'G' FormatGeneral(value, precision);
33 //        case 'R' throw Exception("Invalid blah blah");
34 //        case 'C' FromatCurrency(value, precision, nfi);
35 //        etc...
36 //      }
37 //   }
38 // }
39 //
40 // There is a property in NumberFormatInfo for NegativeSign, though the 
41 // definition of IFormattable just uses '-' in context. So all the 
42 // hardcoded uses of '-' in here may need to be changed to nfi.NegativeSign
43 //
44 // For every integral type.
45 //
46 // Before every Format<Format Type> block there is a small paragraph
47 // detailing its requirements, and a blurb of what I was thinking
48 // at the time.
49 //
50 // Some speedup suggestions to be done when after this appears
51 // to be working properly:
52 //
53 //   * Deal w/ out of range numbers better. Specifically with
54 //     regards to boundry cases such as Long.MinValue etc.
55 //     The previous way of if (value < 0) value = -value;
56 //     fails under this assumption, since the largest
57 //     possible MaxValue is < absolute value of the MinValue.
58 //     I do the first iteration outside of the loop, and then
59 //     convert the number to positive, then continue in the loop.
60 //
61 //   * Replace all occurances of max<Type>Length with their 
62 //     numerical values. Plus the places where things are set
63 //     to max<Type>Length - 1. Hardcode these to numbers.
64 //
65 //   * Move the code for all the NumberToString()'s into the
66 //     the main ToString (string, NumberFormatInfo) method in
67 //     the data types themselves. That way they'd be throwing
68 //     their own exceptions on error and it'd save a function
69 //     call.
70 //
71 //   * For integer to char buffer transformation, you could
72 //     implement the calculations of the 10's and 100's place
73 //     the same time w/ another table to shorten loop time.
74 //
75 //   * Someone smarter can prolly find a much more efficient 
76 //     way of formatting the exponential notation. It's still
77 //     done in pass, just may have too many repositioning
78 //     calculations.
79 //   
80 //   * Decide whether it be better to have functions that
81 //     handle formatting for all types, or just cast their
82 //     values out and format them. Just if library size is
83 //     more important than speed in saving a cast and a 
84 //     function call.
85 //
86
87 using System;
88 using System.Collections;
89 using System.Globalization;
90
91 namespace System {
92
93         public sealed class IntegerFormatter {
94
95                 private static int maxByteLength = 4;
96                 private static int maxShortLength = 6;
97                 private static int maxIntLength = 12;
98                 private static int maxLongLength = 22;
99
100                 private static char[] digitLowerTable;
101 /**
102  * This makes a TypeNotInitialized exception be thrown.
103  *              { '0', '1', '2', '3', '4', '5', '6', '7', 
104  *                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
105  */
106
107                 private static char[] digitUpperTable;
108 /*
109  *              { '0', '1', '2', '3', '4', '5', '6', '7', 
110  *                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
111  */
112
113                 static IntegerFormatter ()
114                 {
115                         int i;
116
117                         digitLowerTable = new char[16];
118                         digitUpperTable = new char[16];
119
120                         for (i = 0; i < 10; i++){
121                                 digitLowerTable[i] = (char) ('0' + i);
122                                 digitUpperTable[i] = (char) ('0' + i);
123                         }
124
125                         char lc = (char ) ('a' - i);
126                         char uc = (char ) ('A' - i);
127                         while (i < 16){
128                                 digitLowerTable[i] = (char) (lc + i);
129                                 digitUpperTable[i] = (char) (uc + i);
130                                 i++;
131                         }
132                 }
133
134                 private static bool IsDigit (char c)
135                 {
136                         return !(c < '0' || c > '9'); 
137                 }
138                 
139                 private static bool IsLetter (char c)
140                 {
141                         return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); 
142                 }
143  
144                 private static bool ParseFormat (string format, out char specifier,  out int precision, out bool custom)
145                 {                                
146                         precision = -1;
147                         specifier = '\0';
148                         custom = false;
149                         
150                         int length = format.Length;
151                         // TODO: Could an empty string be a custom format string?
152                         if (length < 1)
153                                 return false;
154                         
155                         char[] chars = format.ToCharArray ();
156                         specifier = chars[0];
157
158                         // TODO: IsLetter() and IsDigit() should be replaced by Char.Is*()
159                         if (IsLetter(specifier) && length <= 3) {
160                                 switch (length){
161                                 case 1:
162                                         return true;
163                                 case 2:
164                                         if (IsDigit(chars[1])) {
165                                                 precision = chars[1] - '0';
166                                                 return true;
167                                         }
168                                         break;
169                                 case 3:
170                                         if (IsDigit(chars[1]) && IsDigit(chars[2])) {
171                                                 precision = chars[1] - '0';
172                                                 precision = precision * 10 + chars[2] - '0';
173                                                 return true;
174                                         }
175                                         break;
176                                 }
177                                 
178                         }
179                         
180                         // We've got a custom format string.
181                         custom = true;
182                         return true;
183                 }        
184
185                 // ============ Public Interface to all the integer types ============ //
186                 
187                 public static string NumberToString (string format, NumberFormatInfo nfi, byte value)
188                 {
189                         char specifier;
190                         int precision;
191                         bool custom;
192
193                         if (!ParseFormat (format, out specifier, out precision, out custom))
194                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
195                         
196                         if (custom){
197                                 return FormatCustom (format, value, nfi);
198                         }
199
200                         switch(specifier) {
201                         case 'c': return FormatCurrency (value, precision, nfi);
202                         case 'C': return FormatCurrency (value, precision, nfi);
203                         case 'd': return FormatDecimal (value, precision);
204                         case 'D': return FormatDecimal (value, precision);
205                         case 'e': return FormatExponential (value, precision, false);
206                         case 'E': return FormatExponential (value, precision, true);
207                         case 'f': return FormatFixedPoint (value, precision, nfi);      
208                         case 'F': return FormatFixedPoint (value, precision, nfi);      
209                         case 'g': return FormatGeneral (value, precision, nfi, false);
210                         case 'G': return FormatGeneral (value, precision, nfi, true);
211                         case 'n': return FormatNumber (value, precision, nfi);
212                         case 'N': return FormatNumber (value, precision, nfi);
213                         case 'p': return FormatPercent (value, precision, nfi);
214                         case 'P': return FormatPercent (value, precision, nfi);
215                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
216                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
217                         case 'x': return FormatHexadecimal (value, precision, false);
218                         case 'X': return FormatHexadecimal (value, precision, true);
219                         default: 
220                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
221                         }
222                 }               
223
224                 public static string NumberToString (string format, NumberFormatInfo nfi, short value)
225                 {
226                         char specifier;
227                         int precision;
228                         bool custom;
229                         
230                         if (!ParseFormat (format, out specifier, out precision, out custom))
231                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
232                         
233                         if (custom){
234                                 return FormatCustom (format, value, nfi);
235                         }
236
237                         switch(specifier) {
238                         case 'c': return FormatCurrency (value, precision, nfi);
239                         case 'C': return FormatCurrency (value, precision, nfi);
240                         case 'd': return FormatDecimal (value, precision);
241                         case 'D': return FormatDecimal (value, precision);
242                         case 'e': return FormatExponential (value, precision, false);
243                         case 'E': return FormatExponential (value, precision, true);
244                         case 'f': return FormatFixedPoint (value, precision, nfi);      
245                         case 'F': return FormatFixedPoint (value, precision, nfi);      
246                         case 'g': return FormatGeneral (value, precision, nfi, false);
247                         case 'G': return FormatGeneral (value, precision, nfi, true);
248                         case 'n': return FormatNumber (value, precision, nfi);
249                         case 'N': return FormatNumber (value, precision, nfi);
250                         case 'p': return FormatPercent (value, precision, nfi);
251                         case 'P': return FormatPercent (value, precision, nfi);
252                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
253                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this insance"));
254                         case 'x': return FormatHexadecimal (value, precision, false);
255                         case 'X': return FormatHexadecimal (value, precision, true);
256                         default: 
257                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
258                         }
259                 }
260
261                 public static string NumberToString (string format, NumberFormatInfo nfi, int value)
262                 {
263                         char specifier;
264                         int precision;
265                         bool custom;
266                         
267                         if (!ParseFormat (format, out specifier, out precision, out custom))
268                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
269                         
270                         if (custom){
271                                 return FormatCustom (format, value, nfi);
272                         }
273
274                         switch(specifier) {
275                         case 'c': return FormatCurrency (value, precision, nfi);        
276                         case 'C': return FormatCurrency (value, precision, nfi);        
277                         case 'd': return FormatDecimal (value, precision);
278                         case 'D': return FormatDecimal (value, precision);
279                         case 'e': return FormatExponential (value, precision, false);
280                         case 'E': return FormatExponential (value, precision, true);
281                         case 'f': return FormatFixedPoint (value, precision, nfi);      
282                         case 'F': return FormatFixedPoint (value, precision, nfi);      
283                         case 'g': return FormatGeneral (value, precision, nfi, false);
284                         case 'G': return FormatGeneral (value, precision, nfi, true);
285                         case 'n': return FormatNumber (value, precision, nfi);
286                         case 'N': return FormatNumber (value, precision, nfi);
287                         case 'p': return FormatPercent (value, precision, nfi);
288                         case 'P': return FormatPercent (value, precision, nfi);
289                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
290                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
291                         case 'x': return FormatHexadecimal (value, precision, false);
292                         case 'X': return FormatHexadecimal (value, precision, true);
293                         default: 
294                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
295                         }
296                 }
297
298                 public static string NumberToString (string format, NumberFormatInfo nfi, long value)
299                 {
300                         char specifier;
301                         int precision;
302                         bool custom;
303                         
304                         if (!ParseFormat (format, out specifier, out precision, out custom))
305                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
306                         
307                         if (custom){
308                                 return FormatCustom (format, value, nfi);
309                         }
310
311                         switch(specifier) {
312                         case 'c': return FormatCurrency (value, precision, nfi);
313                         case 'C': return FormatCurrency (value, precision, nfi);
314                         case 'd': return FormatDecimal (value, precision);
315                         case 'D': return FormatDecimal (value, precision);
316                         case 'e': return FormatExponential (value, precision, false);
317                         case 'E': return FormatExponential (value, precision, true);
318                         case 'f': return FormatFixedPoint (value, precision, nfi);      
319                         case 'F': return FormatFixedPoint (value, precision, nfi);      
320                         case 'g': return FormatGeneral (value, precision, nfi, false);
321                         case 'G': return FormatGeneral (value, precision, nfi, true);
322                         case 'n': return FormatNumber (value, precision, nfi);
323                         case 'N': return FormatNumber (value, precision, nfi);
324                         case 'p': return FormatPercent (value, precision, nfi);
325                         case 'P': return FormatPercent (value, precision, nfi);
326                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
327                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
328                         case 'x': return FormatHexadecimal (value, precision, false);
329                         case 'X': return FormatHexadecimal (value, precision, true);
330                         default: 
331                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
332                         }                       
333                 }
334
335                 [CLSCompliant (false)]
336                 public static string NumberToString (string format, NumberFormatInfo nfi, sbyte value)
337                 {
338                         char specifier;
339                         int precision;
340                         bool custom;
341                         
342                         if (!ParseFormat (format, out specifier, out precision, out custom))
343                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
344                         
345                         if (custom){
346                                 return FormatCustom (format, value, nfi);
347                         }
348                         
349                         switch(specifier) {
350                         case 'c': return FormatCurrency (value, precision, nfi);
351                         case 'C': return FormatCurrency (value, precision, nfi);
352                         case 'd': return FormatDecimal (value, precision);
353                         case 'D': return FormatDecimal (value, precision);
354                         case 'e': return FormatExponential (value, precision, false);
355                         case 'E': return FormatExponential (value, precision, true);
356                         case 'f': return FormatFixedPoint (value, precision, nfi);      
357                         case 'F': return FormatFixedPoint (value, precision, nfi);      
358                         case 'g': return FormatGeneral (value, precision, nfi, false);
359                         case 'G': return FormatGeneral (value, precision, nfi, true);
360                         case 'n': return FormatNumber (value, precision, nfi);
361                         case 'N': return FormatNumber (value, precision, nfi);
362                         case 'p': return FormatPercent (value, precision, nfi);
363                         case 'P': return FormatPercent (value, precision, nfi);
364                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
365                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
366                         case 'x': return FormatHexadecimal (value, precision, false);
367                         case 'X': return FormatHexadecimal (value, precision, true);
368                         default: 
369                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
370                         }
371                 }
372
373                 [CLSCompliant (false)]
374                 public static string NumberToString (string format, NumberFormatInfo nfi, ushort value)
375                 {
376                         char specifier;
377                         int precision;
378                         bool custom;
379                         
380                         if (!ParseFormat (format, out specifier, out precision, out custom))
381                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
382                         
383                         if (custom){
384                                 return FormatCustom (format, value, nfi);
385                         }
386                         
387                         switch(specifier) {
388                         case 'c': return FormatCurrency (value, precision, nfi);
389                         case 'C': return FormatCurrency (value, precision, nfi);
390                         case 'd': return FormatDecimal (value, precision);
391                         case 'D': return FormatDecimal (value, precision);
392                         case 'e': return FormatExponential (value, precision, false);
393                         case 'E': return FormatExponential (value, precision, true);
394                         case 'f': return FormatFixedPoint (value, precision, nfi);      
395                         case 'F': return FormatFixedPoint (value, precision, nfi);      
396                         case 'g': return FormatGeneral (value, precision, nfi, false);
397                         case 'G': return FormatGeneral (value, precision, nfi, true);
398                         case 'n': return FormatNumber (value, precision, nfi);
399                         case 'N': return FormatNumber (value, precision, nfi);
400                         case 'p': return FormatPercent (value, precision, nfi);
401                         case 'P': return FormatPercent (value, precision, nfi);
402                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
403                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
404                         case 'x': return FormatHexadecimal (value, precision, false);
405                         case 'X': return FormatHexadecimal (value, precision, true);
406                         default: 
407                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
408                         }
409                 }
410
411                 [CLSCompliant (false)]
412                 public static string NumberToString (string format, NumberFormatInfo nfi, uint value)
413                 {
414                         char specifier;
415                         int precision;
416                         bool custom;
417                         
418                         if (!ParseFormat (format, out specifier, out precision, out custom))
419                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
420                         
421                         if (custom){
422                                 return FormatCustom (format, value, nfi);
423                         }
424                         
425                         switch(specifier) {
426                         case 'c': return FormatCurrency (value, precision, nfi);
427                         case 'C': return FormatCurrency (value, precision, nfi);
428                         case 'd': return FormatDecimal (value, precision);
429                         case 'D': return FormatDecimal (value, precision);
430                         case 'e': return FormatExponential (value, precision, false);
431                         case 'E': return FormatExponential (value, precision, true);
432                         case 'f': return FormatFixedPoint (value, precision, nfi);      
433                         case 'F': return FormatFixedPoint (value, precision, nfi);      
434                         case 'g': return FormatGeneral (value, precision, nfi, false);
435                         case 'G': return FormatGeneral (value, precision, nfi, true);
436                         case 'n': return FormatNumber (value, precision, nfi);
437                         case 'N': return FormatNumber (value, precision, nfi);
438                         case 'p': return FormatPercent (value, precision, nfi);
439                         case 'P': return FormatPercent (value, precision, nfi);
440                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
441                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
442                         case 'x': return FormatHexadecimal (value, precision, false);
443                         case 'X': return FormatHexadecimal (value, precision, true);
444                         default: 
445                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
446                         }
447                 }
448
449                 [CLSCompliant (false)]
450                 public static string NumberToString (string format, NumberFormatInfo nfi, ulong value)
451                 {
452                         char specifier;
453                         int precision;
454                         bool custom;
455                         
456                         if (!ParseFormat (format, out specifier, out precision, out custom))
457                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
458                         
459                         if (custom){
460                                 return FormatCustom (format, value, nfi);
461                         }
462                         
463                         switch(specifier) {
464                         case 'c': return FormatCurrency (value, precision, nfi);
465                         case 'C': return FormatCurrency (value, precision, nfi);
466                         case 'd': return FormatDecimal (value, precision);
467                         case 'D': return FormatDecimal (value, precision);
468                         case 'e': return FormatExponential (value, precision, false);
469                         case 'E': return FormatExponential (value, precision, true);
470                         case 'f': return FormatFixedPoint (value, precision, nfi);      
471                         case 'F': return FormatFixedPoint (value, precision, nfi);      
472                         case 'g': return FormatGeneral (value, precision, nfi, false);
473                         case 'G': return FormatGeneral (value, precision, nfi, true);
474                         case 'n': return FormatNumber (value, precision, nfi);
475                         case 'N': return FormatNumber (value, precision, nfi);
476                         case 'p': return FormatPercent (value, precision, nfi);
477                         case 'P': return FormatPercent (value, precision, nfi);
478                         case 'r': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
479                         case 'R': throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
480                         case 'x': return FormatHexadecimal (value, precision, false);
481                         case 'X': return FormatHexadecimal (value, precision, true);
482                         default: 
483                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
484                         }
485                 }
486
487                 // ============ Currency Type Formating ============ //
488
489                 //
490                 //  Currency Format: Used for strings containing a monetary value. The
491                 //  CurrencySymbol, CurrencyGroupSizes, CurrencyGroupSeparator, and
492                 //  CurrencyDecimalSeparator members of a NumberFormatInfo supply
493                 //  the currency symbol, size and separator for digit groupings, and
494                 //  decimal separator, respectively.
495                 //  CurrencyNegativePattern and CurrencyPositivePattern determine the
496                 //  symbols used to represent negative and positive values. For example,
497                 //  a negative value may be prefixed with a minus sign, or enclosed in
498                 //  parentheses.
499                 //  If the precision specifier is omitted
500                 //  NumberFormatInfo.CurrencyDecimalDigits determines the number of
501                 //  decimal places in the string. Results are rounded to the nearest
502                 //  representable value when necessary.
503                 //
504                 //  The pattern of the NumberFormatInfo determines how the output looks, where
505                 //  the dollar sign goes, where the negative sign goes, etc.
506                 //  IFormattable documentation lists the patterns and their values,
507                 //  I have them commented out in the large switch statement
508                 //
509
510                 private static string FormatCurrency (byte value, int precision, NumberFormatInfo nfi) 
511                 {
512                         return FormatCurrency ((uint)value, precision, nfi);
513                 }
514
515                 private static string FormatCurrency (short value, int precision, NumberFormatInfo nfi) 
516                 {
517                         return FormatCurrency ((int)value, precision, nfi);                     
518                 }
519                         
520                 private static string FormatCurrency (int value, int precision, NumberFormatInfo nfi) 
521                 {
522                         int i, j, k;
523                         bool negative = (value < 0);
524
525                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
526                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
527                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
528                         int[] groupSizes = nfi.CurrencyGroupSizes;
529                         int pattern = negative ? nfi.CurrencyNegativePattern : nfi.CurrencyPositivePattern;
530                         int symbolLength = currencySymbol.Length;
531                         
532                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
533                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
534                         decimalSeparator.Length + symbolLength; 
535                         char[] buffy = new char[size];
536                         int position = size;
537
538                         // set up the pattern from IFormattible
539                         if (negative) {
540                                 i = symbolLength; 
541  
542                                 switch (pattern) {
543                                 case 0: // ($nnn)
544                                         buffy[--position] = ')'; 
545                                         break;
546                                 // case 1: // -$nnn
547                                 //      break;
548                                 // case 2: // $-nnn
549                                 //      break;
550                                 case 3: // $nnn-
551                                         buffy[--position] = '-';
552                                         break;
553                                 case 4: // (nnn$)
554                                         buffy[--position] = ')'; 
555                                         do {
556                                                 buffy[--position] = currencySymbol[--i];
557                                         } while (i > 0);
558                                         break;
559                                 case 5: // -nnn$
560                                         do {
561                                                 buffy[--position] = currencySymbol[--i];
562                                         } while (i > 0);
563                                         break;
564                                 case 6: // nnn-$
565                                         do {
566                                                 buffy[--position] = currencySymbol[--i];
567                                         } while (i > 0);
568                                         buffy[--position] = '-'; 
569                                         break;
570                                 case 7: // nnn$-
571                                         buffy[--position] = '-'; 
572                                         do {
573                                                 buffy[--position] = currencySymbol[--i];
574                                         } while (i > 0);
575                                         break;
576                                 case 8: // -nnn $
577                                         do {
578                                                 buffy[--position] = currencySymbol[--i];
579                                         } while (i > 0);
580                                         buffy[--position] = ' '; 
581                                         break;
582                                 // case 9: // -$ nnn
583                                 //      break;
584                                 case 10: // nnn $-
585                                         buffy[--position] = '-'; 
586                                         do {
587                                                 buffy[--position] = currencySymbol[--i];
588                                         } while (i > 0);
589                                         buffy[--position] = ' '; 
590                                         break;
591                                 case 11: // $ nnn-
592                                         buffy[--position] = '-'; 
593                                         break;
594                                 // case 12: // $ -nnn
595                                 //      break;
596                                 case 13: // nnn- $
597                                         do {
598                                                 buffy[--position] = currencySymbol[--i];
599                                         } while (i > 0);
600                                         buffy[--position] = ' '; 
601                                         buffy[--position] = '-'; 
602                                         break;
603                                 case 14: // ($ nnn)
604                                         buffy[--position] = ')'; 
605                                         break;
606                                 case 15: // (nnn $)
607                                         buffy[--position] = ')'; 
608                                         do {
609                                                 buffy[--position] = currencySymbol[--i];
610                                         } while (i > 0);
611                                         break;                          
612                                 }
613                         } else {
614                                 i = symbolLength; 
615                                 switch (pattern) {
616                                 // case 0: // $nnn
617                                 //      break;
618                                 case 1: // nnn$
619                                         do {
620                                                 buffy[--position] = currencySymbol[--i];
621                                         } while (i > 0);
622                                         break;
623                                 // case 2: // $ nnn
624                                 //      break;
625                                 case 3: // nnn $
626                                         do {
627                                                 buffy[--position] = currencySymbol[--i];
628                                         } while (i > 0);
629                                         buffy[--position] = ' '; 
630                                         break;
631                                 }
632                         }
633                         
634                         // right pad it w/ precision 0's
635                         while (padding-- > 0)
636                                 buffy[--position] = '0';
637
638                         // put on decimal separator if we moved over and put a 0 
639                         if (position < size && buffy[position] == '0') {
640                                 i = decimalSeparator.Length; 
641                                 do {
642                                         buffy[--position] = decimalSeparator[--i];
643                                 } while (i > 0);                        
644                         }
645
646                         // loop through, keeping track of where you are in the
647                         // group sizes array and putting out the group separator
648                         // when needed
649                         j = 0;
650                         k = groupSizes[j++];
651
652                         // just in place to take care of the negative boundries (Int32.MinValue)
653                         if (negative) {
654                                 if (value <= -10) {
655                                         buffy[--position] = digitLowerTable[-(value % 10)];
656                                         value = value / -10;
657                                         
658                                         if (--k == 0) {
659                                                 i = groupSeparator.Length; 
660                                                 do {
661                                                         buffy[--position] = groupSeparator[--i];
662                                                 } while (i > 0);
663                                                 
664                                                 k = (j < groupSizes.Length) ? 
665                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
666                                         }
667                                 } else value = -value;
668                         }
669
670                         while (value >= 10) {
671                                 buffy[--position] = digitLowerTable[(value % 10)];
672                                 value /= 10;
673
674                                 if (--k == 0) {
675                                         i = groupSeparator.Length; 
676                                         do {
677                                                 buffy[--position] = groupSeparator[--i];
678                                         } while (i > 0);
679                                         
680                                         k = (j < groupSizes.Length) ? 
681                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
682                                 }
683                         }                
684
685                         buffy[--position] = digitLowerTable[value];
686
687                         // end the pattern on the left hand side
688                         if (negative) {
689                                 i = symbolLength; 
690  
691                                 switch (pattern) {
692                                 case 0: // ($nnn)
693                                         do {
694                                                 buffy[--position] = currencySymbol[--i];
695                                         } while (i > 0);
696                                         buffy[--position] = '('; 
697                                         break;
698                                 case 1: // -$nnn
699                                         do {
700                                                 buffy[--position] = currencySymbol[--i];
701                                         } while (i > 0);
702                                         buffy[--position] = '-'; 
703                                         break;
704                                 case 2: // $-nnn
705                                         buffy[--position] = '-'; 
706                                         do {
707                                                 buffy[--position] = currencySymbol[--i];
708                                         } while (i > 0);
709                                         break;
710                                 case 3: // $nnn-
711                                         do {
712                                                 buffy[--position] = currencySymbol[--i];
713                                         } while (i > 0);
714                                         break;
715                                 case 4: // (nnn$)
716                                         buffy[--position] = '('; 
717                                         break;
718                                 case 5: // -nnn$
719                                         buffy[--position] = '-'; 
720                                         break;
721                                 // case 6: // nnn-$
722                                 //      break;
723                                 // case 7: // nnn$-
724                                 //      break;
725                                 case 8: // -nnn $
726                                         buffy[--position] = '-'; 
727                                         break;
728                                 // case 9: // -$ nnn
729                                 //      break;
730                                 // case 10: // nnn $-
731                                 //      break;
732                                 case 11: // $ nnn-
733                                         buffy[--position] = ' '; 
734                                         do {
735                                                 buffy[--position] = currencySymbol[--i];
736                                         } while (i > 0);
737                                         break;
738                                 case 12: // $ -nnn
739                                         buffy[--position] = '-'; 
740                                         buffy[--position] = ' '; 
741                                         do {
742                                                 buffy[--position] = currencySymbol[--i];
743                                         } while (i > 0);
744                                         break;
745                                 // case 13: // nnn- $
746                                 //      break;
747                                 case 14: // ($ nnn)
748                                         buffy[--position] = ' '; 
749                                         do {
750                                                 buffy[--position] = currencySymbol[--i];
751                                         } while (i > 0);
752                                         buffy[--position] = '('; 
753                                         break;
754                                 case 15: // (nnn $)
755                                         buffy[--position] = '('; 
756                                         break;                          
757                                 }
758                         } else {
759                                 i = symbolLength; 
760                                 switch (pattern) {
761                                 case 0: // $nnn
762                                         do {
763                                                 buffy[--position] = currencySymbol[--i];
764                                         } while (i > 0);
765                                         break;
766                                 // case 1: // nnn$
767                                 //      break;
768                                 case 2: // $ nnn
769                                         buffy[--position] = ' '; 
770                                         do {
771                                                 buffy[--position] = currencySymbol[--i];
772                                         } while (i > 0);
773                                         break;
774                                 // case 3: // nnn $
775                                 //      break;
776                                 }
777                         }
778                         
779                         return new string (buffy, position, (size - position));
780                 }
781
782                 private static string FormatCurrency (long value, int precision, NumberFormatInfo nfi) 
783                 {
784                         int i, j, k;
785                         bool negative = (value < 0);
786
787                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
788                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
789                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
790                         int[] groupSizes = nfi.CurrencyGroupSizes;
791                         int pattern = negative ? nfi.CurrencyNegativePattern : nfi.CurrencyPositivePattern;
792                         int symbolLength = currencySymbol.Length;
793                         
794                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
795                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
796                         decimalSeparator.Length + symbolLength; 
797                         char[] buffy = new char[size];
798                         int position = size;
799
800                         // set up the pattern from IFormattible
801                         if (negative) {
802                                 i = symbolLength; 
803  
804                                 switch (pattern) {
805                                 case 0: // ($nnn)
806                                         buffy[--position] = ')'; 
807                                         break;
808                                 // case 1: // -$nnn
809                                 //      break;
810                                 // case 2: // $-nnn
811                                 //      break;
812                                 case 3: // $nnn-
813                                         buffy[--position] = '-';
814                                         break;
815                                 case 4: // (nnn$)
816                                         buffy[--position] = ')'; 
817                                         do {
818                                                 buffy[--position] = currencySymbol[--i];
819                                         } while (i > 0);
820                                         break;
821                                 case 5: // -nnn$
822                                         do {
823                                                 buffy[--position] = currencySymbol[--i];
824                                         } while (i > 0);
825                                         break;
826                                 case 6: // nnn-$
827                                         do {
828                                                 buffy[--position] = currencySymbol[--i];
829                                         } while (i > 0);
830                                         buffy[--position] = '-'; 
831                                         break;
832                                 case 7: // nnn$-
833                                         buffy[--position] = '-'; 
834                                         do {
835                                                 buffy[--position] = currencySymbol[--i];
836                                         } while (i > 0);
837                                         break;
838                                 case 8: // -nnn $
839                                         do {
840                                                 buffy[--position] = currencySymbol[--i];
841                                         } while (i > 0);
842                                         buffy[--position] = ' '; 
843                                         break;
844                                 // case 9: // -$ nnn
845                                 //      break;
846                                 case 10: // nnn $-
847                                         buffy[--position] = '-'; 
848                                         do {
849                                                 buffy[--position] = currencySymbol[--i];
850                                         } while (i > 0);
851                                         buffy[--position] = ' '; 
852                                         break;
853                                 case 11: // $ nnn-
854                                         buffy[--position] = '-'; 
855                                         break;
856                                 // case 12: // $ -nnn
857                                 //      break;
858                                 case 13: // nnn- $
859                                         do {
860                                                 buffy[--position] = currencySymbol[--i];
861                                         } while (i > 0);
862                                         buffy[--position] = ' '; 
863                                         buffy[--position] = '-'; 
864                                         break;
865                                 case 14: // ($ nnn)
866                                         buffy[--position] = ')'; 
867                                         break;
868                                 case 15: // (nnn $)
869                                         buffy[--position] = ')'; 
870                                         do {
871                                                 buffy[--position] = currencySymbol[--i];
872                                         } while (i > 0);
873                                         break;                          
874                                 }
875                         } else {
876                                 i = symbolLength; 
877                                 switch (pattern) {
878                                 // case 0: // $nnn
879                                 //      break;
880                                 case 1: // nnn$
881                                         do {
882                                                 buffy[--position] = currencySymbol[--i];
883                                         } while (i > 0);
884                                         break;
885                                 // case 2: // $ nnn
886                                 //      break;
887                                 case 3: // nnn $
888                                         do {
889                                                 buffy[--position] = currencySymbol[--i];
890                                         } while (i > 0);
891                                         buffy[--position] = ' '; 
892                                         break;
893                                 }
894                         }
895                         
896                         // right pad it w/ precision 0's
897                         while (padding-- > 0)
898                                 buffy[--position] = '0';
899
900                         // put on decimal separator if we moved over and put a 0 
901                         if (position < size && buffy[position] == '0') {
902                                 i = decimalSeparator.Length; 
903                                 do {
904                                         buffy[--position] = decimalSeparator[--i];
905                                 } while (i > 0);                        
906                         }
907
908                         // loop through, keeping track of where you are in the
909                         // group sizes array and putting out the group separator
910                         // when needed
911                         j = 0;
912                         k = groupSizes[j++];
913                        
914                         if (negative) {
915                                 if (value <= -10) {
916                                         buffy[--position] = digitLowerTable[-(value % 10)];
917                                         value = value / -10;
918                                         
919                                         if (--k == 0) {
920                                                 i = groupSeparator.Length; 
921                                                 do {
922                                                         buffy[--position] = groupSeparator[--i];
923                                                 } while (i > 0);
924                                                 
925                                                 k = (j < groupSizes.Length) ? 
926                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
927                                         }
928                                 } else value = -value;
929                         }
930
931                         while (value >= 10) {
932                                 buffy[--position] = digitLowerTable[(value % 10)];
933                                 value /= 10;
934
935                                 if (--k == 0) {
936                                         i = groupSeparator.Length; 
937                                         do {
938                                                 buffy[--position] = groupSeparator[--i];
939                                         } while (i > 0);
940                                         
941                                         k = (j < groupSizes.Length) ? 
942                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
943                                 }
944                         }                
945
946                         buffy[--position] = digitLowerTable[value];
947
948                         // end the pattern on the left hand side
949                         if (negative) {
950                                 i = symbolLength; 
951  
952                                 switch (pattern) {
953                                 case 0: // ($nnn)
954                                         do {
955                                                 buffy[--position] = currencySymbol[--i];
956                                         } while (i > 0);
957                                         buffy[--position] = '('; 
958                                         break;
959                                 case 1: // -$nnn
960                                         do {
961                                                 buffy[--position] = currencySymbol[--i];
962                                         } while (i > 0);
963                                         buffy[--position] = '-'; 
964                                         break;
965                                 case 2: // $-nnn
966                                         buffy[--position] = '-'; 
967                                         do {
968                                                 buffy[--position] = currencySymbol[--i];
969                                         } while (i > 0);
970                                         break;
971                                 case 3: // $nnn-
972                                         do {
973                                                 buffy[--position] = currencySymbol[--i];
974                                         } while (i > 0);
975                                         break;
976                                 case 4: // (nnn$)
977                                         buffy[--position] = '('; 
978                                         break;
979                                 case 5: // -nnn$
980                                         buffy[--position] = '-'; 
981                                         break;
982                                 // case 6: // nnn-$
983                                 //      break;
984                                 // case 7: // nnn$-
985                                 //      break;
986                                 case 8: // -nnn $
987                                         buffy[--position] = '-'; 
988                                         break;
989                                 // case 9: // -$ nnn
990                                 //      break;
991                                 // case 10: // nnn $-
992                                 //      break;
993                                 case 11: // $ nnn-
994                                         buffy[--position] = ' '; 
995                                         do {
996                                                 buffy[--position] = currencySymbol[--i];
997                                         } while (i > 0);
998                                         break;
999                                 case 12: // $ -nnn
1000                                         buffy[--position] = '-'; 
1001                                         buffy[--position] = ' '; 
1002                                         do {
1003                                                 buffy[--position] = currencySymbol[--i];
1004                                         } while (i > 0);
1005                                         break;
1006                                 // case 13: // nnn- $
1007                                 //      break;
1008                                 case 14: // ($ nnn)
1009                                         buffy[--position] = ' '; 
1010                                         do {
1011                                                 buffy[--position] = currencySymbol[--i];
1012                                         } while (i > 0);
1013                                         buffy[--position] = '('; 
1014                                         break;
1015                                 case 15: // (nnn $)
1016                                         buffy[--position] = '('; 
1017                                         break;                          
1018                                 }
1019                         } else {
1020                                 i = symbolLength; 
1021                                 switch (pattern) {
1022                                 case 0: // $nnn
1023                                         do {
1024                                                 buffy[--position] = currencySymbol[--i];
1025                                         } while (i > 0);
1026                                         break;
1027                                 // case 1: // nnn$
1028                                 //      break;
1029                                 case 2: // $ nnn
1030                                         buffy[--position] = ' '; 
1031                                         do {
1032                                                 buffy[--position] = currencySymbol[--i];
1033                                         } while (i > 0);
1034                                         break;
1035                                 // case 3: // nnn $
1036                                 //      break;
1037                                 }
1038                         }
1039                         
1040                         return new string (buffy, position, (size - position));
1041                 }
1042
1043                 private static string FormatCurrency (sbyte value, int precision, NumberFormatInfo nfi) 
1044                 {
1045                         return FormatCurrency ((int)value, precision, nfi);
1046                 }
1047
1048                 private static string FormatCurrency (ushort value, int precision, NumberFormatInfo nfi) 
1049                 {
1050                         return FormatCurrency ((uint)value, precision, nfi);                    
1051                 }
1052
1053                 private static string FormatCurrency (uint value, int precision, NumberFormatInfo nfi) 
1054                 {
1055                         int i, j, k;
1056
1057                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
1058                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
1059                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
1060                         int[] groupSizes = nfi.CurrencyGroupSizes;
1061                         int pattern = nfi.CurrencyPositivePattern;
1062                         int symbolLength = currencySymbol.Length;
1063                         
1064                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
1065                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
1066                         decimalSeparator.Length + symbolLength; 
1067                         char[] buffy = new char[size];
1068                         int position = size;
1069
1070                         // set up the pattern from IFormattible, no negative
1071                         i = symbolLength; 
1072                         switch (pattern) {
1073                         // case 0: // $nnn
1074                         //      break;
1075                         case 1: // nnn$
1076                                 do {
1077                                         buffy[--position] = currencySymbol[--i];
1078                                 } while (i > 0);
1079                                 break;
1080                         // case 2: // $ nnn
1081                         //      break;
1082                         case 3: // nnn $
1083                                 do {
1084                                         buffy[--position] = currencySymbol[--i];
1085                                 } while (i > 0);
1086                                 buffy[--position] = ' '; 
1087                                 break;
1088                         }
1089                         
1090                         // right pad it w/ precision 0's
1091                         while (padding-- > 0)
1092                                 buffy[--position] = '0';
1093
1094                         // put on decimal separator if we moved over and put a 0 
1095                         if (position < size && buffy[position] == '0') {
1096                                 i = decimalSeparator.Length; 
1097                                 do {
1098                                         buffy[--position] = decimalSeparator[--i];
1099                                 } while (i > 0);                        
1100                         }
1101
1102                         // loop through, keeping track of where you are in the
1103                         // group sizes array and putting out the group separator
1104                         // when needed
1105                         j = 0;
1106                         k = groupSizes[j++];
1107                        
1108                         while (value >= 10) {
1109                                 buffy[--position] = digitLowerTable[(value % 10)];
1110                                 value /= 10;
1111
1112                                 if (--k == 0) {
1113                                         i = groupSeparator.Length; 
1114                                         do {
1115                                                 buffy[--position] = groupSeparator[--i];
1116                                         } while (i > 0);
1117                                         
1118                                         k = (j < groupSizes.Length) ? 
1119                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
1120                                 }
1121                         }                
1122
1123                         buffy[--position] = digitLowerTable[value];
1124
1125                         // end the pattern on the left hand side
1126                         i = symbolLength; 
1127                         switch (pattern) {
1128                         case 0: // $nnn
1129                                 do {
1130                                         buffy[--position] = currencySymbol[--i];
1131                                 } while (i > 0);
1132                                 break;
1133                         // case 1: // nnn$
1134                         //      break;
1135                         case 2: // $ nnn
1136                                 buffy[--position] = ' '; 
1137                                 do {
1138                                         buffy[--position] = currencySymbol[--i];
1139                                 } while (i > 0);
1140                                 break;
1141                         // case 3: // nnn $
1142                                 //      break;
1143                         }
1144                         
1145                         return new string (buffy, position, (size - position));
1146                 }
1147
1148                 private static string FormatCurrency (ulong value, int precision, NumberFormatInfo nfi) 
1149                 {
1150                         int i, j, k;
1151
1152                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
1153                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
1154                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
1155                         int[] groupSizes = nfi.CurrencyGroupSizes;
1156                         int pattern = nfi.CurrencyPositivePattern;
1157                         int symbolLength = currencySymbol.Length;
1158                         
1159                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
1160                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
1161                         decimalSeparator.Length + symbolLength; 
1162                         char[] buffy = new char[size];
1163                         int position = size;
1164
1165                         // set up the pattern from IFormattible, no negative
1166                         i = symbolLength; 
1167                         switch (pattern) {
1168                         // case 0: // $nnn
1169                         //      break;
1170                         case 1: // nnn$
1171                                 do {
1172                                         buffy[--position] = currencySymbol[--i];
1173                                 } while (i > 0);
1174                                 break;
1175                         // case 2: // $ nnn
1176                         //      break;
1177                         case 3: // nnn $
1178                                 do {
1179                                         buffy[--position] = currencySymbol[--i];
1180                                 } while (i > 0);
1181                                 buffy[--position] = ' '; 
1182                                 break;
1183                         }
1184                         
1185                         // right pad it w/ precision 0's
1186                         while (padding-- > 0)
1187                                 buffy[--position] = '0';
1188
1189                         // put on decimal separator if we moved over and put a 0 
1190                         if (position < size && buffy[position] == '0') {
1191                                 i = decimalSeparator.Length; 
1192                                 do {
1193                                         buffy[--position] = decimalSeparator[--i];
1194                                 } while (i > 0);                        
1195                         }
1196
1197                         // loop through, keeping track of where you are in the
1198                         // group sizes array and putting out the group separator
1199                         // when needed
1200                         j = 0;
1201                         k = groupSizes[j++];
1202                        
1203                         while (value >= 10) {
1204                                 buffy[--position] = digitLowerTable[(value % 10)];
1205                                 value /= 10;
1206
1207                                 if (--k == 0) {
1208                                         i = groupSeparator.Length; 
1209                                         do {
1210                                                 buffy[--position] = groupSeparator[--i];
1211                                         } while (i > 0);
1212                                         
1213                                         k = (j < groupSizes.Length) ? 
1214                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
1215                                 }
1216                         }                
1217
1218                         buffy[--position] = digitLowerTable[value];
1219
1220                         // end the pattern on the left hand side
1221                         i = symbolLength; 
1222                         switch (pattern) {
1223                         case 0: // $nnn
1224                                 do {
1225                                         buffy[--position] = currencySymbol[--i];
1226                                 } while (i > 0);
1227                                 break;
1228                         // case 1: // nnn$
1229                         //      break;
1230                         case 2: // $ nnn
1231                                 buffy[--position] = ' '; 
1232                                 do {
1233                                         buffy[--position] = currencySymbol[--i];
1234                                 } while (i > 0);
1235                                 break;
1236                         // case 3: // nnn $
1237                                 //      break;
1238                         }
1239                         
1240                         return new string (buffy, position, (size - position));
1241                 }
1242                 
1243                 // ============ Format Decimal Types ============ //
1244
1245                 //
1246                 // Used only for integral data types. Negative values are 
1247                 // represented by using a '-' sign. The precision specifies
1248                 // how many digits are to appear in the string. If it is >
1249                 // how many digits we need, the left side is padded w/ 0's.
1250                 // If it is smaller than what we need, it is discarded.
1251                 //
1252                 // Fairly simple implementation. Fill the buffer from right
1253                 // to left w/ numbers, then if we still have precision left
1254                 // over, pad w/ zeros.
1255                 //
1256
1257                 private static string FormatDecimal (byte value, int precision) 
1258                 {
1259                         return FormatDecimal ((uint)value, precision);
1260                 }
1261
1262                 private static string FormatDecimal (short value, int precision) 
1263                 {
1264                         return FormatDecimal ((int)value, precision);
1265                 }
1266         
1267                 private static string FormatDecimal (int value, int precision)
1268                 {
1269                         int size = (precision > 0) ? (maxIntLength + precision) : maxIntLength;
1270                         char[] buffy = new char[size];
1271                         int position = size;
1272                         bool negative = (value < 0);
1273                         
1274                         if (negative) 
1275                                 if (value <= -10) {
1276                                         buffy[--position] = digitLowerTable[-(value % 10)];
1277                                         value = value / -10;
1278                                 } else value = -value;
1279                         
1280                         // get our value into a buffer from right to left
1281                         while (value >= 10) {
1282                                 buffy[--position] = digitLowerTable[(value % 10)];
1283                                 value /= 10;
1284                         }
1285                                 
1286                         buffy[--position] = digitLowerTable[value];
1287
1288                         // if we have precision left over, fill with 0's
1289                         precision -= (size - position); 
1290                         while (precision-- > 0 && position > 1) 
1291                                 buffy[--position] = '0';
1292
1293                         if (negative) 
1294                                 buffy[--position] = '-';
1295                         
1296                         return new string (buffy, position, (size - position));  
1297                 }
1298
1299                 private static string FormatDecimal (long value, int precision)
1300                 {
1301                         int size = (precision > 0) ? (maxLongLength + precision) : maxLongLength;
1302                         char[] buffy = new char[size];
1303                         int position = size;
1304                         bool negative = (value < 0);
1305
1306                         if (negative) 
1307                                 if (value <= -10) {
1308                                         buffy[--position] = digitLowerTable[-(value % 10)];
1309                                         value = value / -10;
1310                                 } else value = -value;
1311
1312                         // get our value into a buffer from right to left
1313                         while (value >= 10) {
1314                                 buffy[--position] = digitLowerTable[(value % 10)];
1315                                 value /= 10;
1316                         }
1317                                 
1318                         buffy[--position] = digitLowerTable[value];
1319                         
1320                         // if we have precision left over, fill with 0's
1321                         precision -= (size - position); 
1322                         while (precision-- > 0 && position > 1)
1323                                 buffy[--position] = '0';
1324
1325                         if (negative) 
1326                                 buffy[--position] = '-';
1327                         
1328                         return new string (buffy, position, (size - position));  
1329                 }
1330
1331                 private static string FormatDecimal (sbyte value, int precision) 
1332                 {
1333                         return FormatDecimal ((int)value, precision);
1334                 }
1335
1336                 private static string FormatDecimal (ushort value, int precision) 
1337                 {
1338                         return FormatDecimal ((uint)value, precision);
1339                 }
1340
1341                 private static string FormatDecimal (uint value, int precision)
1342                 {
1343                         int size = (precision > 0) ? (maxIntLength + precision) : maxIntLength;
1344                         char[] buffy = new char[size];
1345                         int position = size;
1346
1347                         // get our value into a buffer from right to left
1348                         while (value >= 10) {
1349                                 buffy[--position] = digitLowerTable[(value % 10)];
1350                                 value /= 10;
1351                         }
1352                                 
1353                         buffy[--position] = digitLowerTable[value];
1354                         
1355                         // if we have precision left over, fill with 0's
1356                         precision -= (size - position); 
1357                         while (precision-- > 0 && position > 1) 
1358                                 buffy[--position] = '0';
1359
1360                         return new string (buffy, position, (size - position));  
1361                 }
1362
1363                 private static string FormatDecimal (ulong value, int precision)
1364                 {
1365                         int size = (precision > 0) ? (maxLongLength + precision) : maxLongLength;
1366                         char[] buffy = new char[size];
1367                         int position = size;
1368
1369                         // get our value into a buffer from right to left
1370                         while (value >= 10) {
1371                                 buffy[--position] = digitLowerTable[(value % 10)];
1372                                 value /= 10;
1373                         }
1374                                 
1375                         buffy[--position] = digitLowerTable[value];
1376                         
1377                         // if we have precision left over, fill with 0's
1378                         precision -= (size - position); 
1379                         while (precision-- > 0 && position > 1)
1380                                 buffy[--position] = '0';
1381
1382                         return new string (buffy, position, (size - position));  
1383                 }
1384
1385                 // ============ Format Exponentials ============ //
1386
1387                 //
1388                 // Used for strings in the format [-]M.DDDDDDe+XXX.
1389                 // Exaclty one non-zero digit must appear in M, w/ 
1390                 // a '-' sign if negative. The precision determines 
1391                 // number of decimal places, if not given go 6 places.
1392                 // If precision > the number of places we need, it
1393                 // is right padded w/ 0's. If it is smaller than what
1394                 // we need, we cut off and round. The format specifier
1395                 // decides whether we use an uppercase E or lowercase e.
1396                 // 
1397                 // Tried to do this in one pass of one buffer, but it
1398                 // wasn't happening. Get a buffer + 7 extra slots for
1399                 // the -, ., E, +, and XXX. Parse the value into another
1400                 // temp buffer, then build the new string. For the
1401                 // integral data types, there are a couple things that
1402                 // can be hardcoded. Since an int and a long can't be
1403                 // larger than 20 something spaces, the first X w/ 
1404                 // always be 0, and the the exponential value will only
1405                 // be 2 digits long. Also integer types w/ always
1406                 // have a positive exponential.
1407                 //
1408                 
1409                 private static string FormatExponential (byte value, int precision, bool upper) 
1410                 {
1411                         return FormatExponential ((uint)value, precision, upper);
1412                 }
1413
1414                 private static string FormatExponential (short value, int precision, bool upper) 
1415                 {
1416                         return FormatExponential ((int)value, precision, upper);
1417                 }
1418
1419                 private static string FormatExponential (int value, int precision, bool upper)
1420                 {
1421                         bool negative = (value < 0);
1422                         int padding = (precision >= 0) ? precision : 6;
1423                         char[] buffy = new char[(padding + 8)];
1424                         char[] tmp = new char [maxIntLength];
1425                         int exponent = 0, position = maxIntLength;
1426                         int exp = 0, idx = 0;
1427                         ulong pow = 10;
1428
1429                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1430                         uint number = (negative) ? (uint)((-(value + 1)) + 1) : (uint)value;
1431
1432                         // need to calculate the number of places to know if we need to round later
1433                         if (negative && value <= -10) {
1434                                 value /= -10;
1435                                 exp++;
1436                         }
1437
1438                         while (value >= 10) {
1439                                 value /= 10;
1440                                 exp++;
1441                         }
1442                                                         
1443                         if (exp > padding) {
1444
1445                                 // highest number we should goto before we round
1446                                 while (idx++ <= padding)
1447                                         pow *= 10;
1448
1449                                 // get our value into a buffer
1450                                 while (number > pow) {
1451                                         tmp[--position] = digitLowerTable[(number % 10)];
1452                                         number /= 10;
1453                                         exponent++;
1454                                 }
1455                         
1456                                 number += 5;
1457                         }
1458
1459                         while (number >= 10) {
1460                                 tmp[--position] = digitLowerTable[(number% 10)];
1461                                 number /= 10;
1462                                 exponent++;
1463                         }                      
1464
1465                         tmp[--position] = digitLowerTable[number];
1466                         idx = 0;
1467                         
1468                         // go left to right in filling up new string
1469                         if (negative)
1470                                 buffy[idx++] = '-';
1471
1472                         // we know we have at least one in there, followed 
1473                         // by a decimal point
1474                         buffy[idx++] = tmp[position++];
1475                         if (precision != 0)
1476                                 buffy[idx++] = '.';
1477
1478                         // copy over the remaining digits until we run out,
1479                         // or we've passed our specified precision
1480                         while (padding > 0 && position < maxIntLength) {
1481                                 buffy[idx++] = tmp[position++];
1482                                 padding--;
1483                         }
1484                         
1485                         // if we still have more precision to go, add some
1486                         // zeros
1487                         while (padding > 0) {
1488                                 buffy[idx++] = '0';
1489                                 padding--;
1490                         }
1491                         
1492                         // we know these next 3 spots
1493                         buffy[idx++] = upper ? 'E' : 'e';
1494                         buffy[idx++] = '+';
1495                         buffy[idx++] = '0';
1496                         
1497                         // next two digits depend on our length
1498                         if (exponent >= 10) {
1499                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1500                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1501                         } else { 
1502                                 buffy[idx++] = '0';
1503                                 buffy[idx] = digitLowerTable[exponent];
1504                         }
1505
1506                         return new string(buffy, 0, ++idx); 
1507                 }
1508
1509                 private static string FormatExponential (long value, int precision, bool upper)
1510                 {
1511                         bool negative = (value < 0);
1512                         int padding = (precision >= 0) ? precision : 6;
1513                         char[] buffy = new char[(padding + 8)];
1514                         char[] tmp = new char [maxLongLength];
1515                         int exponent = 0, position = maxLongLength;
1516                         int exp = 0, idx = 0;
1517                         ulong pow = 10;
1518
1519                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1520                         ulong number = (negative) ? (ulong)((-(value + 1)) + 1) : (ulong)value;
1521
1522                         // need to calculate the number of places to know if we need to round later
1523                         if (negative && value <= -10) {
1524                                 value /= -10;
1525                                 exp++;
1526                         }
1527
1528                         while (value >= 10) {
1529                                 value /= 10;
1530                                 exp++;
1531                         }
1532                                                         
1533                         if (exp > padding) {
1534                                 
1535                                 // highest number we should goto before we round
1536                                 while (idx++ <= padding)
1537                                         pow *= 10;
1538                                 
1539                                 // get our value into a buffer
1540                                 while (number > pow) {
1541                                         tmp[--position] = digitLowerTable[(number % 10)];
1542                                         number /= 10;
1543                                         exponent++;
1544                                 }
1545                         
1546                                 number += 5;
1547                         }
1548
1549                         while (number >= 10) {
1550                                 tmp[--position] = digitLowerTable[(number% 10)];
1551                                 number /= 10;
1552                                 exponent++;
1553                         }                      
1554
1555                         tmp[--position] = digitLowerTable[number];
1556                         idx = 0;
1557
1558                         // go left to right in filling up new string
1559                         if (negative)
1560                                 buffy[idx++] = '-';
1561
1562                         // we know we have at least one in there, followed 
1563                         // by a decimal point
1564                         buffy[idx++] = tmp[position++];
1565                         if (precision != 0)
1566                                 buffy[idx++] = '.';
1567
1568                         // copy over the remaining digits until we run out,
1569                         // or we've passed our specified precision
1570                         while (padding > 0 && position < maxLongLength) {
1571                                 buffy[idx++] = tmp[position++];
1572                                 padding--;
1573                         }
1574                         
1575                         // if we still have more precision to go, add some
1576                         // zeros
1577                         while (padding > 0) {
1578                                 buffy[idx++] = '0';
1579                                 padding--;
1580                         }
1581                         
1582                         // we know these next 3 spots
1583                         buffy[idx++] = upper ? 'E' : 'e';
1584                         buffy[idx++] = '+';
1585                         buffy[idx++] = '0';
1586                         
1587                         // next two digits depend on our length
1588                         if (exponent >= 10) {
1589                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1590                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1591                         } else { 
1592                                 buffy[idx++] = '0';
1593                                 buffy[idx] = digitLowerTable[exponent];
1594                         }
1595
1596                         return new string(buffy, 0, ++idx); 
1597                 }
1598
1599                 private static string FormatExponential (sbyte value, int precision, bool upper) 
1600                 {
1601                         return FormatExponential ((int)value, precision, upper);
1602                 }
1603
1604                 private static string FormatExponential (ushort value, int precision, bool upper) 
1605                 {
1606                         return FormatExponential ((uint)value, precision, upper);
1607                 }
1608
1609                 private static string FormatExponential (uint value, int precision, bool upper)
1610                 {
1611                         int padding = (precision >= 0) ? precision : 6;
1612                         char[] buffy = new char[(padding + 8)];
1613                         char[] tmp = new char [maxIntLength];
1614                         int exponent = 0, position = maxIntLength;
1615                         int exp = 0, idx = 0;
1616                         ulong pow = 10;
1617                         ulong number = (ulong)value;
1618
1619                         // need to calculate the number of places to know if we need to round later
1620                         while (value >= 10) {
1621                                 value /= 10;
1622                                 exp++;
1623                         }
1624                                                         
1625                         if (exp > padding) {
1626
1627                                 // highest number we should goto before we round
1628                                 while (idx++ <= padding)
1629                                         pow *= 10;
1630                                 
1631                                 // get our value into a buffer
1632                                 while (number > pow) {
1633                                         tmp[--position] = digitLowerTable[(number % 10)];
1634                                         number /= 10;
1635                                         exponent++;
1636                                 }
1637                                 
1638                                 number += 5;
1639                         }
1640
1641                         while (number >= 10) {
1642                                 tmp[--position] = digitLowerTable[(number% 10)];
1643                                 number /= 10;
1644                                 exponent++;
1645                         }                      
1646
1647                         tmp[--position] = digitLowerTable[number];
1648                         idx = 0;
1649
1650                         // we know we have at least one in there, followed 
1651                         // by a decimal point
1652                         buffy[idx++] = tmp[position++];
1653                         if (precision != 0)
1654                                 buffy[idx++] = '.';
1655
1656                         // copy over the remaining digits until we run out,
1657                         // or we've passed our specified precision
1658                         while (padding > 0 && position < maxIntLength) {
1659                                 buffy[idx++] = tmp[position++];
1660                                 padding--;
1661                         }
1662                         
1663                         // if we still have more precision to go, add some
1664                         // zeros
1665                         while (padding > 0) {
1666                                 buffy[idx++] = '0';
1667                                 padding--;
1668                         }
1669                         
1670                         // we know these next 3 spots
1671                         buffy[idx++] = upper ? 'E' : 'e';
1672                         buffy[idx++] = '+';
1673                         buffy[idx++] = '0';
1674                         
1675                         // next two digits depend on our length
1676                         if (exponent >= 10) {
1677                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1678                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1679                         } else { 
1680                                 buffy[idx++] = '0';
1681                                 buffy[idx] = digitLowerTable[exponent];
1682                         }
1683
1684                         return new string(buffy, 0, ++idx); 
1685                 }
1686
1687                 private static string FormatExponential (ulong value, int precision, bool upper)
1688                 {
1689                         int padding = (precision >= 0) ? precision : 6;
1690                         char[] buffy = new char[(padding + 8)];
1691                         char[] tmp = new char [maxLongLength];
1692                         int exponent = 0, position = maxLongLength;
1693                         int exp = 0, idx = 0;
1694                         ulong pow = 10;
1695                         ulong number = value;
1696
1697                         // need to calculate the number of places to know if we need to round later
1698                         while (value >= 10) {
1699                                 value /= 10;
1700                                 exp++;
1701                         }
1702                                                         
1703                         if (exp > padding) {
1704
1705                                 // highest number we should goto before we round
1706                                 while (idx++ <= padding)
1707                                         pow *= 10;
1708
1709                                 // get our value into a buffer
1710                                 while (number > pow) {
1711                                         tmp[--position] = digitLowerTable[(number % 10)];
1712                                         number /= 10;
1713                                         exponent++;
1714                                 }
1715                         
1716                                 number += 5;
1717                         }
1718
1719                         while (number >= 10) {
1720                                 tmp[--position] = digitLowerTable[(number% 10)];
1721                                 number /= 10;
1722                                 exponent++;
1723                         }                      
1724
1725                         tmp[--position] = digitLowerTable[number];
1726                         idx = 0;
1727
1728                         // we know we have at least one in there, followed 
1729                         // by a decimal point
1730                         buffy[idx++] = tmp[position++];
1731                         if (precision != 0)
1732                                 buffy[idx++] = '.';
1733
1734                         // copy over the remaining digits until we run out,
1735                         // or we've passed our specified precision
1736                         while (padding > 0 && position < maxLongLength) {
1737                                 buffy[idx++] = tmp[position++];
1738                                 padding--;
1739                         }
1740                         
1741                         // if we still have more precision to go, add some
1742                         // zeros
1743                         while (padding > 0) {
1744                                 buffy[idx++] = '0';
1745                                 padding--;
1746                         }
1747                         
1748                         // we know these next 3 spots
1749                         buffy[idx++] = upper ? 'E' : 'e';
1750                         buffy[idx++] = '+';
1751                         buffy[idx++] = '0';
1752                         
1753                         // next two digits depend on our length
1754                         if (exponent >= 10) {
1755                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1756                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1757                         } else { 
1758                                 buffy[idx++] = '0';
1759                                 buffy[idx] = digitLowerTable[exponent];
1760                         }
1761
1762                         return new string(buffy, 0, ++idx); 
1763                 }
1764
1765                 // ============ Format Fixed Points ============ //
1766
1767                 //
1768                 // Used for strings in the following form "[-]M.DD...D"
1769                 // At least one non-zero digit precedes the '.', w/ a 
1770                 // '-' before that if negative. Precision specifies number
1771                 // of decimal places 'D' to go. If not given, use
1772                 // NumberFormatInfo.NumbeDecimalDigits. Results are rounded
1773                 // if necessary. 
1774                 //
1775                 // Fairly simple implementation for integral types. Going
1776                 // from right to left, fill up precision number of 0's,
1777                 // plop a . down, then go for our number. 
1778                 //
1779
1780                 private static string FormatFixedPoint (byte value, int precision, NumberFormatInfo nfi)
1781                 {
1782                         return FormatFixedPoint ((uint)value, precision, nfi);
1783                 }
1784
1785                 private static string FormatFixedPoint (short value, int precision, NumberFormatInfo nfi)
1786                 {
1787                         return FormatFixedPoint ((int)value, precision, nfi);
1788                 }
1789
1790                 private static string FormatFixedPoint (int value, int precision, NumberFormatInfo nfi)
1791                 {
1792                         int padding = (precision >= 0) ? (precision + maxIntLength) : (nfi.NumberDecimalDigits + maxIntLength);
1793                         char[] buffy = new char[padding];
1794                         int position = padding;
1795                         bool negative = (value < 0);
1796                         
1797                         // fill up w/ precision # of 0's
1798                         while (position > (maxIntLength - 1)) 
1799                                 buffy[--position] = '0';
1800
1801                         if (precision != 0)
1802                                 buffy[position--] = '.';
1803
1804                         if (negative)
1805                                 if (value <= -10) {
1806                                         buffy[position--] = digitLowerTable[-(value % 10)];
1807                                         value = value / -10;
1808                                 } else value = -value;
1809                         
1810                         // fill up w/ the value
1811                         while (value >= 10) {
1812                                 buffy[position--] = digitLowerTable[(value % 10)];
1813                                 value = value / 10;
1814                         }
1815
1816                         buffy[position] = digitLowerTable[value];
1817
1818                         if (negative) 
1819                                 buffy[--position] = '-';
1820                         
1821                         return new string (buffy, position, (padding - position));
1822                 }
1823
1824                 private static string FormatFixedPoint (long value, int precision, NumberFormatInfo nfi)
1825                 {
1826                         int padding = (precision >= 0) ? (precision + maxLongLength) : (nfi.NumberDecimalDigits + maxLongLength);
1827                         char[] buffy = new char[padding];
1828                         int position = padding;
1829                         bool negative = (value < 0);
1830                         
1831                         // fill up w/ precision # of 0's
1832                         while (position > (maxLongLength - 1)) 
1833                                 buffy[--position] = '0';
1834
1835                         if (precision != 0)
1836                                 buffy[position--] = '.';
1837
1838                         if (negative)
1839                                 if (value <= -10) {
1840                                         buffy[position--] = digitLowerTable[-(value % 10)];
1841                                         value = value / -10;
1842                                 } else value = -value;
1843                         
1844                         // fill up w/ the value
1845                         while (value >= 10) {
1846                                 buffy[position--] = digitLowerTable[(value % 10)];
1847                                 value = value / 10;
1848                         }
1849
1850                         buffy[position] = digitLowerTable[value];
1851
1852                         if (negative) 
1853                                 buffy[--position] = '-';
1854                         
1855                         return new string (buffy, position, (padding - position));
1856                 }
1857
1858                 private static string FormatFixedPoint (sbyte value, int precision, NumberFormatInfo nfi)
1859                 {
1860                         return FormatFixedPoint ((int)value, precision, nfi);
1861                 }
1862
1863                 private static string FormatFixedPoint (ushort value, int precision, NumberFormatInfo nfi)
1864                 {
1865                         return FormatFixedPoint ((uint)value, precision, nfi);
1866                 }
1867
1868                 private static string FormatFixedPoint (uint value, int precision, NumberFormatInfo nfi)
1869                 {
1870                         int padding = (precision >= 0) ? (precision + maxIntLength) : (nfi.NumberDecimalDigits + maxIntLength);
1871                         char[] buffy = new char[padding];
1872                         int position = padding;
1873
1874                         // fill up w/ precision # of 0's
1875                         while (position > (maxIntLength - 1)) 
1876                                 buffy[--position] = '0';
1877
1878                         if (precision != 0)
1879                                 buffy[position--] = '.';
1880
1881                         // fill up w/ the value
1882                         while (value >= 10) {
1883                                 buffy[position--] = digitLowerTable[(value % 10)];
1884                                 value = value / 10;
1885                         }
1886
1887                         buffy[position] = digitLowerTable[value];
1888                         
1889                         return new string (buffy, position, (padding - position));
1890                 }
1891
1892                 private static string FormatFixedPoint (ulong value, int precision, NumberFormatInfo nfi)
1893                 {
1894                         int padding = (precision >= 0) ? (precision + maxLongLength) : (nfi.NumberDecimalDigits + maxLongLength);
1895                         char[] buffy = new char[padding];
1896                         int position = padding;
1897
1898                         // fill up w/ precision # of 0's
1899                         while (position > (maxLongLength - 1)) 
1900                                 buffy[--position] = '0';
1901
1902                         if (precision != 0)
1903                                 buffy[position--] = '.';
1904
1905                         // fill up w/ the value
1906                         while (value >= 10) {
1907                                 buffy[position--] = digitLowerTable[(value % 10)];
1908                                 value = value / 10;
1909                         }
1910
1911                         buffy[position] = digitLowerTable[value];
1912                         
1913                         return new string (buffy, position, (padding - position));
1914                 }
1915
1916                 // ============ Format General ============ //
1917                 
1918                 //
1919                 // Strings are formatted in either Fixed Point or Exponential
1920                 // format. Results are rounded when needed. If no precision is
1921                 // given, the defaults are:
1922                 //
1923                 // short & ushort: 5
1924                 // int & uint: 10
1925                 // long & ulong: 19
1926                 // float: 7
1927                 // double: 15
1928                 // decimal: 29
1929                 //
1930                 // The value is formatted using fixed-point if exponent >= -4
1931                 // and exponent < precision, where exponent is he exponenent of
1932                 // the value in exponential format. The decimal point and trailing
1933                 // zeros are removed when possible.
1934                 //
1935                 // For all other values, exponential format is used. The case of
1936                 // the format specifier determines whether 'e' or 'E' prefixes
1937                 // the exponent.
1938                 // 
1939                 // In either case, the number of digits that appear in the result
1940                 // (not including the exponent) will not exceed the value of the
1941                 // precision. The result is rounded as needed.
1942                 //
1943                 // Integral values are formatted using Fixed Point whenever
1944                 // precision is omitted. (This actually doesn't make sense when
1945                 // coupled w/ the 1st paragraph).
1946                 //              
1947                 // Okay, so the decimal point is removed along with any trailing
1948                 // zeros. So, ignoring the last paragraph, we can consider an int
1949                 // ToString() to format it w/ exponential format w/ a default
1950                 // precision of 10, but since it will just be .00000000, it's
1951                 // discarded.
1952                 //
1953
1954                 internal static string FormatGeneral (byte value, int precision, NumberFormatInfo nfi, bool upper) {
1955                         return FormatGeneral ((uint)value, precision, nfi, upper);
1956                 }
1957
1958                 internal static string FormatGeneral (short value, int precision, NumberFormatInfo nfi, bool upper) {
1959                         return FormatGeneral ((int)value, precision, nfi, upper);
1960                 }
1961
1962                 internal static string FormatGeneral (int value, int precision, NumberFormatInfo nfi, bool upper) 
1963                 {
1964                         bool negative = (value < 0);
1965                         char[] tmp = new char [maxIntLength];
1966                         int exponent = 0;
1967                         int position = maxIntLength;
1968                         
1969                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1970                         uint number = (negative) ? (uint)((-(value + 1)) + 1) : (uint)value;
1971
1972                         // get number into a buffer, going to be doing this no matter what
1973                         if (negative)
1974                                 if (value <= -10) {
1975                                         tmp[--position] = digitLowerTable[-(value % 10)];
1976                                         value /= -10;
1977                                         exponent++;
1978                                 } else value = -value;
1979
1980                         while (value >= 10) {
1981                                 tmp[--position] = digitLowerTable[(value % 10)];
1982                                 value /= 10;
1983                                 exponent++;
1984                         }
1985                         
1986                         tmp[--position] = digitLowerTable[value];
1987
1988                         // integral values are formatted using fixed point when precision
1989                         // is not specified. But also trailing decimal point and zeros are
1990                         // discared. So for int's it will always be .00, so just compute
1991                         // here and save the call to FormatFixedPoint & trim.
1992                         if (precision <= 0 || exponent < precision) {
1993                                 if (negative) 
1994                                         tmp[--position] = '-';
1995                                 
1996                                 return new string (tmp, position, (maxIntLength - position)); 
1997                         }
1998
1999                         // else our exponent was > precision, use exponential format
2000                         // precision = number of digits to show. 
2001                         int idx = 0;
2002                         ulong pow = 1;
2003
2004                         exponent = 0;
2005                         position = maxIntLength;
2006                         
2007                         // Loop through while our number is less than the 10 ^ precision, then
2008                         // add 5 to that to round it out, and keep continuing
2009                         while (idx++ <= precision)
2010                                 pow *= 10;
2011                         
2012                         while (number > pow) {
2013                                 tmp[--position] = digitLowerTable[(number % 10)];
2014                                 number /= 10;
2015                                 exponent++;
2016                         }
2017
2018                         number += 5;
2019
2020                         while (number >= 10) {
2021                                 tmp[--position] = digitLowerTable[(number % 10)];
2022                                 number /= 10;
2023                                 exponent++;
2024                         }
2025
2026                         tmp[--position] = digitLowerTable[number];
2027
2028                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2029                         // and reuse pow for size
2030                         idx = position;
2031                         position = 0;
2032                         pow = (ulong)(precision + 6);
2033                         char[] buffy = new char[pow];
2034
2035                         if (negative)
2036                                 buffy[position++] = '-';
2037                         
2038                         buffy[position++] = tmp[idx++];
2039                         buffy[position] = '.';
2040
2041                         // for the remaining precisions copy over rounded tmp
2042                         precision--;
2043                         while (precision-- > 0)
2044                                 buffy[++position] = tmp[idx++];
2045
2046                         // get rid of ending zeros
2047                         while (buffy[position] == '0')
2048                                 position--;
2049
2050                         // if we backed up all the way to the ., over write it
2051                         if (buffy[position] != '.')
2052                                 position++;                     
2053
2054                         // ints can only be +, e or E depending on format, plus XX
2055                         buffy[position++] = upper ? 'E' : 'e';
2056                         buffy[position++] = '+';
2057
2058                         if (exponent >= 10) {
2059                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2060                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2061                         } else { 
2062                                 buffy[position++] = '0';
2063                                 buffy[position++] = digitLowerTable[exponent];
2064                         }
2065                         
2066                         return new string (buffy, 0, position);
2067                 }
2068
2069                 internal static string FormatGeneral (long value, int precision, NumberFormatInfo nfi, bool upper) 
2070                 {
2071                         bool negative = (value < 0);
2072                         char[] tmp = new char [maxLongLength];
2073                         int exponent = 0;
2074                         int position = maxLongLength;
2075
2076                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
2077                         ulong number = (negative) ? (ulong)(-(value + 1) + 1) : (ulong)value;
2078
2079                         // get number into a buffer, going to be doing this no matter what
2080                         if (negative)
2081                                 if (value <= -10) {
2082                                         tmp[--position] = digitLowerTable[-(value % 10)];
2083                                         value /= -10;
2084                                 } else value = -value;
2085
2086                         while (value >= 10) {
2087                                 tmp[--position] = digitLowerTable[(value % 10)];
2088                                 value /= 10;
2089                         }
2090                         
2091                         tmp[--position] = digitLowerTable[value];
2092                         exponent = (maxLongLength - position) - 1;
2093
2094                         // integral values are formatted using fixed point when precision
2095                         // is not specified. But also trailing decimal point and zeros are
2096                         // discared. So for int's it will always be .00, so just compute
2097                         // here and save the call to FormatFixedPoint & trim.
2098                         if (precision <= 0 || exponent < precision) {
2099                                 if (negative) 
2100                                         tmp[--position] = '-';
2101                                 
2102                                 return new string (tmp, position, (maxLongLength - position)); 
2103                         }
2104
2105                         // else our exponent was > precision, use exponential format
2106                         // precision = number of digits to show. 
2107                         int idx = 0;
2108                         ulong pow = 1;
2109
2110                         exponent = 0;
2111                         position = maxLongLength;
2112
2113                         // Loop through while our number is less than the 10 ^ precision, then
2114                         // add 5 to that to round it out, and keep continuing
2115                         while (idx++ <= precision)
2116                                 pow *= 10;
2117                         
2118                         while (number > pow) {
2119                                 tmp[--position] = digitLowerTable[(number % 10)];
2120                                 number /= 10;
2121                                 exponent++;
2122                         }
2123
2124                         number += 5;
2125
2126                         while (number >= 10) {
2127                                 tmp[--position] = digitLowerTable[(number % 10)];
2128                                 number /= 10;
2129                                 exponent++;
2130                         }
2131
2132                         tmp[--position] = digitLowerTable[number];
2133
2134                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2135                         // and reuse pow for size
2136                         idx = position;
2137                         position = 0;
2138                         pow = (ulong)precision + 6;
2139                         char[] buffy = new char[pow];
2140
2141                         if (negative)
2142                                 buffy[position++] = '-';
2143                         
2144                         buffy[position++] = tmp[idx++];
2145                         buffy[position] = '.';
2146
2147                         // for the remaining precisions copy over rounded tmp
2148                         precision--;
2149                         while (precision-- > 0)
2150                                 buffy[++position] = tmp[idx++];
2151
2152                         // get rid of ending zeros
2153                         while (buffy[position] == '0')
2154                                 position--;
2155
2156                         // if we backed up all the way to the ., over write it
2157                         if (buffy[position] != '.')
2158                                 position++;                     
2159
2160                         // ints can only be +, e or E depending on format, plus XX
2161                         buffy[position++] = upper ? 'E' : 'e';
2162                         buffy[position++] = '+';
2163
2164                         if (exponent >= 10) {
2165                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2166                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2167                         } else { 
2168                                 buffy[position++] = '0';
2169                                 buffy[position++] = digitLowerTable[exponent];
2170                         }
2171                         
2172                         return new string (buffy, 0, position);
2173                 }
2174
2175                 internal static string FormatGeneral (sbyte value, int precision, NumberFormatInfo nfi, bool upper) {
2176                         return FormatGeneral ((int)value, precision, nfi, upper);
2177                 }
2178
2179                 internal static string FormatGeneral (ushort value, int precision, NumberFormatInfo nfi, bool upper) {
2180                         return FormatGeneral ((uint)value, precision, nfi, upper);
2181                 }
2182
2183                 internal static string FormatGeneral (uint value, int precision, NumberFormatInfo nfi, bool upper) 
2184                 {
2185                         char[] tmp = new char [maxIntLength];
2186                         int exponent = 0;
2187                         int position = maxIntLength;
2188                         ulong number = (ulong)value;
2189
2190                         // get number into a buffer, going to be doing this no matter what
2191                         while (value >= 10) {
2192                                 tmp[--position] = digitLowerTable[(value % 10)];
2193                                 value /= 10;
2194                         }
2195                         
2196                         tmp[--position] = digitLowerTable[value];
2197                         exponent = (maxIntLength - position) - 1;
2198
2199                         // integral values are formatted using fixed point when precision
2200                         // is not specified. But also trailing decimal point and zeros are
2201                         // discared. So for int's it will always be .00, so just compute
2202                         // here and save the call to FormatFixedPoint & trim.
2203                         if (precision <= 0 || exponent < precision) 
2204                                 return new string (tmp, position, (maxIntLength - position)); 
2205
2206                         // else our exponent was > precision, use exponential format
2207                         // precision = number of digits to show. 
2208                         int idx = 0;
2209                         ulong pow = 1;
2210
2211                         exponent = 0;
2212                         position = maxIntLength;
2213                                                 
2214                         // Loop through while our number is less than the 10 ^ precision, then
2215                         // add 5 to that to round it out, and keep continuing
2216                         while (idx++ <= precision)
2217                                 pow *= 10;
2218
2219                         while (number > pow) {
2220                                 tmp[--position] = digitLowerTable[(number % 10)];
2221                                 number /= 10;
2222                                 exponent++;
2223                         }
2224
2225                         number += 5;
2226
2227                         while (number >= 10) {
2228                                 tmp[--position] = digitLowerTable[(number % 10)];
2229                                 number /= 10;
2230                                 exponent++;
2231                         }
2232
2233                         tmp[--position] = digitLowerTable[number];      
2234
2235                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2236                         // and reuse pow for size
2237                         idx = position;
2238                         position = 0;
2239                         pow = (ulong)(precision + 6);
2240                         char[] buffy = new char[pow];
2241
2242                         buffy[position++] = tmp[idx++];
2243                         buffy[position] = '.';
2244
2245                         // for the remaining precisions copy over rounded tmp
2246                         precision--;
2247                         while (precision-- > 0)
2248                                 buffy[++position] = tmp[idx++];
2249
2250                         // get rid of ending zeros
2251                         while (buffy[position] == '0')
2252                                 position--;
2253
2254                         // if we backed up all the way to the ., over write it
2255                         if (buffy[position] != '.')
2256                                 position++;                     
2257
2258                         // ints can only be +, e or E depending on format, plus XX
2259                         buffy[position++] = upper ? 'E' : 'e';
2260                         buffy[position++] = '+';
2261
2262                         if (exponent >= 10) {
2263                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2264                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2265                         } else { 
2266                                 buffy[position++] = '0';
2267                                 buffy[position++] = digitLowerTable[exponent];
2268                         }
2269                         
2270                         return new string (buffy, 0, position);
2271                 }
2272
2273                 internal static string FormatGeneral (ulong value, int precision, NumberFormatInfo nfi, bool upper) 
2274                 {
2275                         char[] tmp = new char [maxLongLength];
2276                         int exponent = 0;
2277                         int position = maxLongLength;
2278                         ulong number = value;
2279
2280                         // get number into a buffer, going to be doing this no matter what
2281                         while (value >= 10) {
2282                                 tmp[--position] = digitLowerTable[(value % 10)];
2283                                 value /= 10;
2284                                 exponent++;
2285                         }
2286                         
2287                         tmp[--position] = digitLowerTable[value];
2288
2289                         // integral values are formatted using fixed point when precision
2290                         // is not specified. But also trailing decimal point and zeros are
2291                         // discared. So for int's it will always be .00, so just compute
2292                         // here and save the call to FormatFixedPoint & trim.
2293                         if (precision <= 0 || exponent < precision) 
2294                                 return new string (tmp, position, (maxLongLength - position)); 
2295
2296                         // else our exponent was > precision, use exponential format
2297                         // precision = number of digits to show. 
2298                         int idx = 0;
2299                         ulong pow = 1;
2300
2301                         exponent = 0;
2302                         position = maxLongLength;
2303
2304                         // Loop through while our number is less than the 10 ^ precision, then
2305                         // add 5 to that to round it out, and keep continuing
2306                         while (idx++ <= precision)
2307                                 pow *= 10;
2308                         
2309                         while (number > pow) {
2310                                 tmp[--position] = digitLowerTable[(number % 10)];
2311                                 number /= 10;
2312                                 exponent++;
2313                         }
2314
2315                         number += 5;
2316
2317                         while (number >= 10) {
2318                                 tmp[--position] = digitLowerTable[(number % 10)];
2319                                 number /= 10;
2320                                 exponent++;
2321                         }
2322
2323                         tmp[--position] = digitLowerTable[number];
2324
2325                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2326                         // and reuse pow for size
2327                         idx = position;
2328                         position = 0;
2329                         pow = (ulong)precision + 6;
2330                         char[] buffy = new char[pow];
2331
2332                         buffy[position++] = tmp[idx++];
2333                         buffy[position] = '.';
2334
2335                         // for the remaining precisions copy over rounded tmp
2336                         precision--;
2337                         while (precision-- > 0)
2338                                 buffy[++position] = tmp[idx++];
2339
2340                         // get rid of ending zeros
2341                         while (buffy[position] == '0')
2342                                 position--;
2343
2344                         // if we backed up all the way to the ., over write it
2345                         if (buffy[position] != '.')
2346                                 position++;                     
2347
2348                         // ints can only be +, e or E depending on format, plus XX
2349                         buffy[position++] = upper ? 'E' : 'e';
2350                         buffy[position++] = '+';
2351
2352                         if (exponent >= 10) {
2353                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2354                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2355                         } else { 
2356                                 buffy[position++] = '0';
2357                                 buffy[position++] = digitLowerTable[exponent];
2358                         }
2359                         
2360                         return new string (buffy, 0, position);
2361                 }
2362
2363                 // ============ Format Number ============ //
2364
2365                 // 
2366                 // Used for strings in the following form "[-]d,ddd,ddd.dd...d"
2367                 // The minus sign only appears if it is negative. At least one
2368                 // non-zero digit preceeds the decimal separator. The precision
2369                 // specifier determines the number of decimal places. If it is 
2370                 // not given, use NumberFormatInfo.NumberDecimalDigits.
2371                 // The NumberGroupSizes, NumberGroupSeparator, and NumberDecimalSeparator
2372                 // members of NumberFormatInfo supply the size and separator
2373                 // for digit groupings. See IFormattable.
2374                 //
2375                 // The group sizes is an array of ints that determine the grouping
2376                 // of numbers. All digits are in the range 1-9, with the last digit
2377                 // being between 0-9. The number formats the string backwards, with
2378                 // the last digit being the group size for the rest of (leftmost) the
2379                 // the string, 0 being none.
2380                 //
2381                 // For instance:
2382                 //              groupSizes = { 3, 2, 1, 0 }; 
2383                 //              int n = 1234567890 => "1234,5,67,890"
2384                 //              groupSizes = { 3, 2, 1 }; 
2385                 //              int n = 1234567890 => "1,2,3,4,5,67,890"
2386                 //              groupSizes = { 2, 0 };
2387                 //              int n = 1234567890 => "1234567,90";
2388                 //
2389                 // Not too difficult, jsut keep track of where you are in the array
2390                 // and when to print the separator
2391                 //
2392                 // The max size of the buffer is assume we have a separator every 
2393                 // number, plus the precision on the end, plus a spot for the negative
2394                 // and a spot for decimal separator.
2395                 //
2396
2397                 private static string FormatNumber (byte value, int precision, NumberFormatInfo nfi) {
2398                         return FormatNumber ((uint)value, precision, nfi);
2399                 }
2400
2401                 private static string FormatNumber (short value, int precision, NumberFormatInfo nfi) {
2402                         return FormatNumber ((int)value, precision, nfi);
2403                 }
2404
2405                 private static string FormatNumber (int value, int precision, NumberFormatInfo nfi) 
2406                 {
2407                         int i, j, k;
2408                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2409                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2410                         int[] groupSizes = nfi.NumberGroupSizes;
2411
2412                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2413                         int pattern = nfi.NumberNegativePattern;
2414                         int size = maxIntLength + (maxIntLength * groupSeparator.Length) + padding +
2415                         decimalSeparator.Length + 4;
2416                         char[] buffy = new char[size];
2417                         int position = size;
2418                         bool negative = (value < 0);
2419                         
2420                         // pattern for negative values, defined in NumberFormatInfo
2421                         if (negative) {
2422                                 switch (pattern) {
2423                                 case 0: // (nnn)
2424                                         buffy[--position] = ')'; 
2425                                         break;
2426                                 // case 1: // -nnn
2427                                 //      break;
2428                                 // case 2: // - nnn
2429                                 //      break;
2430                                 case 3: // nnn-
2431                                         buffy[--position] = '-'; 
2432                                         break;
2433                                 case 4: // nnn -
2434                                         buffy[--position] = '-'; 
2435                                         buffy[--position] = ' '; 
2436                                         break;
2437                                 }
2438                         }
2439
2440                         // right pad it w/ precision 0's
2441                         while (padding-- > 0)
2442                                 buffy[--position] = '0';
2443
2444                         // put on decimal separator
2445                         if (position != size) {
2446                                 i = decimalSeparator.Length; 
2447                                 do {
2448                                         buffy[--position] = decimalSeparator[--i];
2449                                 } while (i > 0);                        
2450                         }
2451
2452                         // loop through, keeping track of where you are in the
2453                         // group sizes array and putting out the group separator
2454                         // when needed
2455                         j = 0;
2456                         k = groupSizes[j++];
2457
2458                         // negative hack for numbers past MinValue
2459                         if (negative)
2460                                 if (value <= -10) {
2461                                         buffy[--position] = digitLowerTable[-(value % 10)];
2462                                         value = value / -10;
2463                                         
2464                                         if (--k == 0) {
2465                                                 i = groupSeparator.Length; 
2466                                                 do {
2467                                                         buffy[--position] = groupSeparator[--i];
2468                                                 } while (i > 0);
2469                                                 
2470                                                 k = (j < groupSizes.Length) ? 
2471                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2472                                         }
2473                                 } else value = -value;
2474
2475                         while (value >= 10) {
2476                                 buffy[--position] = digitLowerTable[(value % 10)];
2477                                 value /= 10;
2478
2479                                 if (--k == 0) {
2480                                         i = groupSeparator.Length; 
2481                                         do {
2482                                                 buffy[--position] = groupSeparator[--i];
2483                                         } while (i > 0);
2484                                         
2485                                         k = (j < groupSizes.Length) ? 
2486                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2487                                 }
2488                         }                
2489
2490                         buffy[--position] = digitLowerTable[value];
2491
2492                         // pattern for negative values, defined in NumberFormatInfo
2493                         if (negative) {
2494                                 switch (pattern) {
2495                                 case 0: // (nnn)
2496                                         buffy[--position] = '('; 
2497                                         break;
2498                                 case 1: // -nnn
2499                                         buffy[--position] = '-'; 
2500                                         break;
2501                                 case 2: // - nnn
2502                                         buffy[--position] = ' '; 
2503                                         buffy[--position] = '-'; 
2504                                         break;
2505                                 // case 3: // nnn-
2506                                 //      break;
2507                                 // case 4: // nnn -
2508                                 //      break;
2509                                 }
2510                         }
2511                         
2512                         return new string (buffy, position, (size - position));
2513                 }
2514
2515                 private static string FormatNumber (long value, int precision, NumberFormatInfo nfi) 
2516                 {
2517                         int i, j, k;
2518                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2519                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2520                         int[] groupSizes = nfi.NumberGroupSizes;
2521
2522                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2523                         int pattern = nfi.NumberNegativePattern;
2524                         int size = maxLongLength + (maxLongLength * groupSeparator.Length) + padding +
2525                         decimalSeparator.Length + 4;
2526                         char[] buffy = new char[size];
2527                         int position = size;
2528                         bool negative = (value < 0);
2529                         
2530                         // pattern for negative values, defined in NumberFormatInfo
2531                         if (negative) {
2532                                 switch (pattern) {
2533                                 case 0: // (nnn)
2534                                         buffy[--position] = ')'; 
2535                                         break;
2536                                 // case 1: // -nnn
2537                                 //      break;
2538                                 // case 2: // - nnn
2539                                 //      break;
2540                                 case 3: // nnn-
2541                                         buffy[--position] = '-'; 
2542                                         break;
2543                                 case 4: // nnn -
2544                                         buffy[--position] = '-'; 
2545                                         buffy[--position] = ' '; 
2546                                         break;
2547                                 }
2548                         }
2549
2550                         // right pad it w/ precision 0's
2551                         while (padding-- > 0)
2552                                 buffy[--position] = '0';
2553                                                 
2554                         // put on decimal separator
2555                         if (position != size) {
2556                                 i = decimalSeparator.Length; 
2557                                 do {
2558                                         buffy[--position] = decimalSeparator[--i];
2559                                 } while (i > 0);                        
2560                         }
2561
2562                         // loop through, keeping track of where you are in the
2563                         // group sizes array and putting out the group separator
2564                         // when needed
2565                         j = 0;
2566                         k = groupSizes[j++];
2567
2568                         // negative hack for numbers past MinValue
2569                         if (negative)
2570                                 if (value <= -10) {
2571                                         buffy[--position] = digitLowerTable[-(value % 10)];
2572                                         value = value / -10;
2573                                         
2574                                         if (--k == 0) {
2575                                                 i = groupSeparator.Length; 
2576                                                 do {
2577                                                         buffy[--position] = groupSeparator[--i];
2578                                                 } while (i > 0);
2579                                                 
2580                                                 k = (j < groupSizes.Length) ? 
2581                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2582                                         }
2583                                 } else value = -value;
2584
2585                         while (value >= 10) {
2586                                 buffy[--position] = digitLowerTable[(value % 10)];
2587                                 value /= 10;
2588
2589                                 if (--k == 0) {
2590                                         i = groupSeparator.Length; 
2591                                         do {
2592                                                 buffy[--position] = groupSeparator[--i];
2593                                         } while (i > 0);
2594                                         
2595                                         k = (j < groupSizes.Length) ? 
2596                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2597                                 }
2598                         }                
2599
2600                         buffy[--position] = digitLowerTable[value];
2601
2602                         // pattern for negative values, defined in NumberFormatInfo
2603                         if (negative) {
2604                                 switch (pattern) {
2605                                 case 0: // (nnn)
2606                                         buffy[--position] = '('; 
2607                                         break;
2608                                 case 1: // -nnn
2609                                         buffy[--position] = '-'; 
2610                                         break;
2611                                 case 2: // - nnn
2612                                         buffy[--position] = ' '; 
2613                                         buffy[--position] = '-'; 
2614                                         break;
2615                                 // case 3: // nnn-
2616                                 //      break;
2617                                 // case 4: // nnn -
2618                                 //      break;
2619                                 }
2620                         }
2621                         
2622                         return new string (buffy, position, (size - position));
2623                 }
2624
2625                 private static string FormatNumber (sbyte value, int precision, NumberFormatInfo nfi) {
2626                         return FormatNumber ((int)value, precision, nfi);
2627                 }
2628
2629                 private static string FormatNumber (ushort value, int precision, NumberFormatInfo nfi) {
2630                         return FormatNumber ((uint)value, precision, nfi);
2631                 }
2632
2633                 private static string FormatNumber (uint value, int precision, NumberFormatInfo nfi) 
2634                 {
2635                         int i, j, k;
2636                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2637                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2638                         int[] groupSizes = nfi.NumberGroupSizes;
2639
2640                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2641                         int size = maxIntLength + (maxIntLength * groupSeparator.Length) + padding +
2642                         decimalSeparator.Length + 2;
2643                         char[] buffy = new char[size];
2644                         int position = size;
2645                         
2646                         // right pad it w/ precision 0's
2647                         while (padding-- > 0)
2648                                 buffy[--position] = '0';
2649                                                 
2650                         // put on decimal separator
2651                         if (position != size) {
2652                                 i = decimalSeparator.Length; 
2653                                 do {
2654                                         buffy[--position] = decimalSeparator[--i];
2655                                 } while (i > 0);                        
2656                         }
2657
2658                         // loop through, keeping track of where you are in the
2659                         // group sizes array and putting out the group separator
2660                         // when needed
2661                         j = 0;
2662                         k = groupSizes[j++];
2663
2664                         while (value >= 10) {
2665                                 buffy[--position] = digitLowerTable[(value % 10)];
2666                                 value /= 10;
2667
2668                                 if (--k == 0) {
2669                                         i = groupSeparator.Length; 
2670                                         do {
2671                                                 buffy[--position] = groupSeparator[--i];
2672                                         } while (i > 0);
2673                                         
2674                                         k = (j < groupSizes.Length) ? 
2675                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2676                                 }
2677                         }                
2678
2679                         buffy[--position] = digitLowerTable[value];
2680
2681                         return new string (buffy, position, (size - position));
2682                 }
2683
2684                 private static string FormatNumber (ulong value, int precision, NumberFormatInfo nfi) 
2685                 {
2686                         int i, j, k;
2687                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2688                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2689                         int[] groupSizes = nfi.NumberGroupSizes;
2690
2691                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2692                         int size = maxLongLength + (maxLongLength * groupSeparator.Length) + padding +
2693                         decimalSeparator.Length + 2;
2694                         char[] buffy = new char[size];
2695                         int position = size;
2696                         
2697                         // right pad it w/ precision 0's
2698                         while (padding-- > 0)
2699                                 buffy[--position] = '0';
2700                         
2701                         // put on decimal separator
2702                         if (position != size) {
2703                                 i = decimalSeparator.Length; 
2704                                 do {
2705                                         buffy[--position] = decimalSeparator[--i];
2706                                 } while (i > 0);                        
2707                         }
2708
2709                         // loop through, keeping track of where you are in the
2710                         // group sizes array and putting out the group separator
2711                         // when needed
2712                         j = 0;
2713                         k = groupSizes[j++];
2714
2715                         while (value >= 10) {
2716                                 buffy[--position] = digitLowerTable[(value % 10)];
2717                                 value /= 10;
2718
2719                                 if (--k == 0) {
2720                                         i = groupSeparator.Length; 
2721                                         do {
2722                                                 buffy[--position] = groupSeparator[--i];
2723                                         } while (i > 0);
2724                                         
2725                                         k = (j < groupSizes.Length) ? 
2726                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2727                                 }
2728                         }                
2729
2730                         buffy[--position] = digitLowerTable[value];
2731
2732                         return new string (buffy, position, (size - position));
2733                 }               
2734
2735                 // ============ Percent Formatting ============ //
2736
2737                 //
2738                 //  Percent Format: Used for strings containing a percentage. The
2739                 //  PercentSymbol, PercentGroupSizes, PercentGroupSeparator, and
2740                 //  PercentDecimalSeparator members of a NumberFormatInfo supply
2741                 //  the Percent symbol, size and separator for digit groupings, and
2742                 //  decimal separator, respectively.
2743                 //  PercentNegativePattern and PercentPositivePattern determine the
2744                 //  symbols used to represent negative and positive values. For example,
2745                 //  a negative value may be prefixed with a minus sign, or enclosed in
2746                 //  parentheses.
2747                 //  If no precision is specified, the number of decimal places in the result
2748                 //  is set by NumberFormatInfo.PercentDecimalDigits. Results are
2749                 //  rounded to the nearest representable value when necessary.
2750                 //  The result is scaled by 100 (.99 becomes 99%).
2751                 //
2752                 //  The pattern of the number determines how the output looks, where
2753                 //  the percent sign goes, where the negative sign goes, etc.
2754                 //  IFormattable documentation lists the patterns and their values,
2755                 //  I have them commented out in the switch statement
2756                 //
2757
2758                 private static string FormatPercent (byte value, int precision, NumberFormatInfo nfi) 
2759                 {
2760                         return FormatPercent ((uint)value, precision, nfi);
2761                 }
2762
2763                 private static string FormatPercent (short value, int precision, NumberFormatInfo nfi) 
2764                 {
2765                         return FormatPercent ((int)value, precision, nfi);
2766                 }
2767
2768                 private static string FormatPercent (int value, int precision, NumberFormatInfo nfi) 
2769                 {
2770                         int i, j, k;
2771                         bool negative = (value < 0);
2772
2773                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
2774                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
2775                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
2776                         int[] groupSizes = nfi.PercentGroupSizes;
2777                         int pattern = negative ? nfi.PercentNegativePattern : nfi.PercentPositivePattern;
2778                         int symbolLength = percentSymbol.Length;
2779                         
2780                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
2781                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
2782                         decimalSeparator.Length + symbolLength; 
2783                         char[] buffy = new char[size];
2784                         int position = size;
2785
2786                         // set up the pattern from IFormattible
2787                         if (negative) {
2788                                 i = symbolLength; 
2789  
2790                                 switch (pattern) {
2791                                 case 0: // -nnn %
2792                                         do {
2793                                                 buffy[--position] = percentSymbol[--i];
2794                                         } while (i > 0);
2795                                         buffy[--position] = ' '; 
2796                                         break;
2797                                 case 1: // -nnn%
2798                                         do {
2799                                                 buffy[--position] = percentSymbol[--i];
2800                                         } while (i > 0);
2801                                         break;
2802                                 // case 2: // -%nnn
2803                                 //      break;
2804                                 }
2805                         } else {
2806                                 i = symbolLength; 
2807                                 switch (pattern) {
2808                                 case 0: // nnn %
2809                                         do {
2810                                                 buffy[--position] = percentSymbol[--i];
2811                                         } while (i > 0);
2812                                         buffy[--position] = ' ';                                        
2813                                         break;
2814                                 case 1: // nnn%
2815                                         do {
2816                                                 buffy[--position] = percentSymbol[--i];
2817                                         } while (i > 0);
2818                                         break;
2819                                 // case 2: // %nnn
2820                                 //      break;
2821                                 }
2822                         }
2823                         
2824                         // right pad it w/ precision 0's
2825                         while (padding-- > 0)
2826                                 buffy[--position] = '0';
2827
2828                         // put on decimal separator if we moved over and put a 0 
2829                         if (position < size && buffy[position] == '0') {
2830                                 i = decimalSeparator.Length; 
2831                                 do {
2832                                         buffy[--position] = decimalSeparator[--i];
2833                                 } while (i > 0);                        
2834                         }
2835
2836                         // loop through, keeping track of where you are in the
2837                         // group sizes array and putting out the group separator
2838                         // when needed
2839                         j = 0;
2840                         k = groupSizes[j++];
2841
2842                         // all values are multiplied by 100, so tack on two 0's
2843                         if (value != 0) 
2844                                 for (int c = 0; c < 2; c++) {
2845                                         buffy[--position] = '0';
2846                                         
2847                                         if (--k == 0) {
2848                                                 i = groupSeparator.Length; 
2849                                                 do {
2850                                                         buffy[--position] = groupSeparator[--i];
2851                                                 } while (i > 0);
2852                                                 
2853                                                 k = (j < groupSizes.Length) ? 
2854                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2855                                         }
2856                                 }
2857
2858                         // negative hack for numbers past MinValue
2859                         if (negative)
2860                                 if (value <= -10) {
2861                                         buffy[--position] = digitLowerTable[-(value % 10)];
2862                                         value = value / -10;
2863                                         
2864                                         if (--k == 0) {
2865                                                 i = groupSeparator.Length; 
2866                                                 do {
2867                                                         buffy[--position] = groupSeparator[--i];
2868                                                 } while (i > 0);
2869                                                 
2870                                                 k = (j < groupSizes.Length) ? 
2871                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2872                                         }
2873                                 } else value = -value;
2874
2875                         while (value >= 10) {
2876                                 buffy[--position] = digitLowerTable[(value % 10)];
2877                                 value /= 10;
2878
2879                                 if (--k == 0) {
2880                                         i = groupSeparator.Length; 
2881                                         do {
2882                                                 buffy[--position] = groupSeparator[--i];
2883                                         } while (i > 0);
2884                                         
2885                                         k = (j < groupSizes.Length) ? 
2886                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2887                                 }
2888                         }                
2889
2890                         buffy[--position] = digitLowerTable[value];
2891
2892                         // end the pattern on the left hand side
2893                         if (negative) {
2894                                 i = symbolLength; 
2895  
2896                                 switch (pattern) {
2897                                 case 0: // -nnn %
2898                                         buffy[--position] = '-'; 
2899                                         break;
2900                                 case 1: // -nnn%
2901                                         buffy[--position] = '-'; 
2902                                         break;
2903                                 case 2: // -%nnn
2904                                         do {
2905                                                 buffy[--position] = percentSymbol[--i];
2906                                         } while (i > 0);
2907                                         buffy[--position] = '-'; 
2908                                         break;
2909                                 }
2910                         } else {
2911                                 i = symbolLength; 
2912                                 switch (pattern) {
2913                                 // case 0: // nnn %
2914                                 //      break;
2915                                 // case 1: // nnn%
2916                                 //      break;
2917                                 case 2: // %nnn
2918                                         do {
2919                                                 buffy[--position] = percentSymbol[--i];
2920                                         } while (i > 0);
2921                                         break;
2922                                 }
2923                         }
2924                         
2925                         return new string (buffy, position, (size - position));
2926                 }
2927
2928                 private static string FormatPercent (long value, int precision, NumberFormatInfo nfi) 
2929                 {
2930                         int i, j, k;
2931                         bool negative = (value < 0);
2932
2933                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
2934                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
2935                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
2936                         int[] groupSizes = nfi.PercentGroupSizes;
2937                         int pattern = negative ? nfi.PercentNegativePattern : nfi.PercentPositivePattern;
2938                         int symbolLength = percentSymbol.Length;
2939                         
2940                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
2941                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
2942                         decimalSeparator.Length + symbolLength; 
2943                         char[] buffy = new char[size];
2944                         int position = size;
2945
2946                         // set up the pattern from IFormattible
2947                         if (negative) {
2948                                 i = symbolLength; 
2949  
2950                                 switch (pattern) {
2951                                 case 0: // -nnn %
2952                                         do {
2953                                                 buffy[--position] = percentSymbol[--i];
2954                                         } while (i > 0);
2955                                         buffy[--position] = ' '; 
2956                                         break;
2957                                 case 1: // -nnn%
2958                                         do {
2959                                                 buffy[--position] = percentSymbol[--i];
2960                                         } while (i > 0);
2961                                         break;
2962                                 // case 2: // -%nnn
2963                                 //      break;
2964                                 }
2965                         } else {
2966                                 i = symbolLength; 
2967                                 switch (pattern) {
2968                                 case 0: // nnn %
2969                                         do {
2970                                                 buffy[--position] = percentSymbol[--i];
2971                                         } while (i > 0);
2972                                         buffy[--position] = ' ';                                        
2973                                         break;
2974                                 case 1: // nnn%
2975                                         do {
2976                                                 buffy[--position] = percentSymbol[--i];
2977                                         } while (i > 0);
2978                                         break;
2979                                 // case 2: // %nnn
2980                                 //      break;
2981                                 }
2982                         }
2983                         
2984                         // right pad it w/ precision 0's
2985                         while (padding-- > 0)
2986                                 buffy[--position] = '0';
2987
2988                         // put on decimal separator if we moved over and put a 0 
2989                         if (position < size && buffy[position] == '0') {
2990                                 i = decimalSeparator.Length; 
2991                                 do {
2992                                         buffy[--position] = decimalSeparator[--i];
2993                                 } while (i > 0);                        
2994                         }
2995
2996                         // loop through, keeping track of where you are in the
2997                         // group sizes array and putting out the group separator
2998                         // when needed
2999                         j = 0;
3000                         k = groupSizes[j++];
3001
3002                         // all values are multiplied by 100, so tack on two 0's
3003                         if (value != 0) 
3004                                 for (int c = 0; c < 2; c++) {
3005                                         buffy[--position] = '0';
3006                                         
3007                                         if (--k == 0) {
3008                                                 i = groupSeparator.Length; 
3009                                                 do {
3010                                                         buffy[--position] = groupSeparator[--i];
3011                                                 } while (i > 0);
3012                                                 
3013                                                 k = (j < groupSizes.Length) ? 
3014                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3015                                         }
3016                                 }
3017
3018                         // negative hack for numbers past MinValue
3019                         if (negative)
3020                                 if (value <= -10) {
3021                                         buffy[--position] = digitLowerTable[-(value % 10)];
3022                                         value = value / -10;
3023                                         
3024                                         if (--k == 0) {
3025                                                 i = groupSeparator.Length; 
3026                                                 do {
3027                                                         buffy[--position] = groupSeparator[--i];
3028                                                 } while (i > 0);
3029                                                 
3030                                                 k = (j < groupSizes.Length) ? 
3031                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3032                                         }
3033                                 } else value = -value;
3034
3035                         while (value >= 10) {
3036                                 buffy[--position] = digitLowerTable[(value % 10)];
3037                                 value /= 10;
3038
3039                                 if (--k == 0) {
3040                                         i = groupSeparator.Length; 
3041                                         do {
3042                                                 buffy[--position] = groupSeparator[--i];
3043                                         } while (i > 0);
3044                                         
3045                                         k = (j < groupSizes.Length) ? 
3046                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3047                                 }
3048                         }                
3049
3050                         buffy[--position] = digitLowerTable[value];
3051
3052                         // end the pattern on the left hand side
3053                         if (negative) {
3054                                 i = symbolLength; 
3055  
3056                                 switch (pattern) {
3057                                 case 0: // -nnn %
3058                                         buffy[--position] = '-'; 
3059                                         break;
3060                                 case 1: // -nnn%
3061                                         buffy[--position] = '-'; 
3062                                         break;
3063                                 case 2: // -%nnn
3064                                         do {
3065                                                 buffy[--position] = percentSymbol[--i];
3066                                         } while (i > 0);
3067                                         buffy[--position] = '-'; 
3068                                         break;
3069                                 }
3070                         } else {
3071                                 i = symbolLength; 
3072                                 switch (pattern) {
3073                                 // case 0: // nnn %
3074                                 //      break;
3075                                 // case 1: // nnn%
3076                                 //      break;
3077                                 case 2: // %nnn
3078                                         do {
3079                                                 buffy[--position] = percentSymbol[--i];
3080                                         } while (i > 0);
3081                                         break;
3082                                 }
3083                         }
3084                         
3085                         return new string (buffy, position, (size - position));
3086                 }
3087
3088                 private static string FormatPercent (sbyte value, int precision, NumberFormatInfo nfi) 
3089                 {
3090                         return FormatPercent ((int)value, precision, nfi);
3091                 }
3092
3093                 private static string FormatPercent (ushort value, int precision, NumberFormatInfo nfi) 
3094                 {
3095                         return FormatPercent ((uint)value, precision, nfi);
3096                 }
3097
3098                 private static string FormatPercent (uint value, int precision, NumberFormatInfo nfi) 
3099                 {
3100                         int i, j, k;
3101
3102                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
3103                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
3104                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
3105                         int[] groupSizes = nfi.PercentGroupSizes;
3106                         int pattern = nfi.PercentPositivePattern;
3107                         int symbolLength = percentSymbol.Length;
3108                         
3109                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
3110                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
3111                         decimalSeparator.Length + symbolLength; 
3112                         char[] buffy = new char[size];
3113                         int position = size;
3114
3115                         // set up the pattern from IFormattible
3116                         i = symbolLength;                       
3117                         switch (pattern) {
3118                         case 0: // -nnn %
3119                                 do {
3120                                         buffy[--position] = percentSymbol[--i];
3121                                 } while (i > 0);
3122                                 buffy[--position] = ' '; 
3123                                 break;
3124                         case 1: // -nnn%
3125                                 do {
3126                                         buffy[--position] = percentSymbol[--i];
3127                                 } while (i > 0);
3128                                 break;
3129                         // case 2: // -%nnn
3130                         //      break;
3131                         }
3132
3133                         // right pad it w/ precision 0's
3134                         while (padding-- > 0)
3135                                 buffy[--position] = '0';
3136
3137                         // put on decimal separator if we moved over and put a 0 
3138                         if (position < size && buffy[position] == '0') {
3139                                 i = decimalSeparator.Length; 
3140                                 do {
3141                                         buffy[--position] = decimalSeparator[--i];
3142                                 } while (i > 0);                        
3143                         }
3144
3145                         // loop through, keeping track of where you are in the
3146                         // group sizes array and putting out the group separator
3147                         // when needed
3148                         j = 0;
3149                         k = groupSizes[j++];
3150
3151                         if (value != 0) 
3152                                 for (int c = 0; c < 2; c++) {
3153                                         buffy[--position] = '0';
3154                                         
3155                                         if (--k == 0) {
3156                                                 i = groupSeparator.Length; 
3157                                                 do {
3158                                                         buffy[--position] = groupSeparator[--i];
3159                                                 } while (i > 0);
3160                                                 
3161                                                 k = (j < groupSizes.Length) ? 
3162                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3163                                         }
3164                                 }
3165
3166                         while (value >= 10) {
3167                                 buffy[--position] = digitLowerTable[(value % 10)];
3168                                 value /= 10;
3169
3170                                 if (--k == 0) {
3171                                         i = groupSeparator.Length; 
3172                                         do {
3173                                                 buffy[--position] = groupSeparator[--i];
3174                                         } while (i > 0);
3175                                         
3176                                         k = (j < groupSizes.Length) ? 
3177                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3178                                 }
3179                         }                
3180
3181                         buffy[--position] = digitLowerTable[value];
3182
3183                         i = symbolLength; 
3184                         switch (pattern) {
3185                         // case 0: // nnn %
3186                         //      break;
3187                         // case 1: // nnn%
3188                         //      break;
3189                         case 2: // %nnn
3190                                 do {
3191                                         buffy[--position] = percentSymbol[--i];
3192                                 } while (i > 0);
3193                                 break;
3194                         }
3195                         
3196                         return new string (buffy, position, (size - position));
3197                 }
3198
3199                 private static string FormatPercent (ulong value, int precision, NumberFormatInfo nfi) 
3200                 {
3201                         int i, j, k;
3202
3203                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
3204                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
3205                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
3206                         int[] groupSizes = nfi.PercentGroupSizes;
3207                         int pattern = nfi.PercentPositivePattern;
3208                         int symbolLength = percentSymbol.Length;
3209                         
3210                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
3211                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
3212                         decimalSeparator.Length + symbolLength; 
3213                         char[] buffy = new char[size];
3214                         int position = size;
3215
3216                         // set up the pattern from IFormattible
3217                         i = symbolLength;                       
3218                         switch (pattern) {
3219                         case 0: // -nnn %
3220                                 do {
3221                                         buffy[--position] = percentSymbol[--i];
3222                                 } while (i > 0);
3223                                 buffy[--position] = ' '; 
3224                                 break;
3225                         case 1: // -nnn%
3226                                 do {
3227                                         buffy[--position] = percentSymbol[--i];
3228                                 } while (i > 0);
3229                                 break;
3230                         // case 2: // -%nnn
3231                         //      break;
3232                         }
3233
3234                         // right pad it w/ precision 0's
3235                         while (padding-- > 0)
3236                                 buffy[--position] = '0';
3237
3238                         // put on decimal separator if we moved over and put a 0 
3239                         if (position < size && buffy[position] == '0') {
3240                                 i = decimalSeparator.Length; 
3241                                 do {
3242                                         buffy[--position] = decimalSeparator[--i];
3243                                 } while (i > 0);                        
3244                         }
3245
3246                         // loop through, keeping track of where you are in the
3247                         // group sizes array and putting out the group separator
3248                         // when needed
3249                         j = 0;
3250                         k = groupSizes[j++];
3251
3252                         if (value != 0) 
3253                                 for (int c = 0; c < 2; c++) {
3254                                         buffy[--position] = '0';
3255                                         
3256                                         if (--k == 0) {
3257                                                 i = groupSeparator.Length; 
3258                                                 do {
3259                                                         buffy[--position] = groupSeparator[--i];
3260                                                 } while (i > 0);
3261                                                 
3262                                                 k = (j < groupSizes.Length) ? 
3263                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3264                                         }
3265                                 }
3266                         
3267                         while (value >= 10) {
3268                                 buffy[--position] = digitLowerTable[(value % 10)];
3269                                 value /= 10;
3270
3271                                 if (--k == 0) {
3272                                         i = groupSeparator.Length; 
3273                                         do {
3274                                                 buffy[--position] = groupSeparator[--i];
3275                                         } while (i > 0);
3276                                         
3277                                         k = (j < groupSizes.Length) ? 
3278                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3279                                 }
3280                         }                
3281
3282                         buffy[--position] = digitLowerTable[value];
3283
3284                         i = symbolLength; 
3285                         switch (pattern) {
3286                         // case 0: // nnn %
3287                         //      break;
3288                         // case 1: // nnn%
3289                         //      break;
3290                         case 2: // %nnn
3291                                 do {
3292                                         buffy[--position] = percentSymbol[--i];
3293                                 } while (i > 0);
3294                                 break;
3295                         }
3296                         
3297                         return new string (buffy, position, (size - position));
3298                 }
3299
3300                 // ============ Format Hexadecimal ============ //
3301
3302                 // 
3303                 // For strings in base 16. Only valid w/ integers. Precision 
3304                 // specifies number of digits in the string, if it specifies
3305                 // more digits than we need, left pad w/ 0's. The case of the
3306                 // the format specifier 'X' or 'x' determines lowercase or
3307                 // capital digits in the output.
3308                 //
3309                 // Whew. Straight forward Hex formatting, however only
3310                 // go 8 places max when dealing with an int (not counting
3311                 // precision padding) and 16 when dealing with a long. This
3312                 // is to cut off the loop when dealing with negative values,
3313                 // which will loop forever when you hit -1;
3314                 //
3315
3316                 private static string FormatHexadecimal (byte value, int precision, bool upper)
3317                 {                    
3318                         if (precision < 0) precision = 0;
3319                         int size = maxByteLength + precision;
3320                         char[] buffy = new char[size];
3321                         char[] table = upper ? digitUpperTable : digitLowerTable;
3322                         int position = size;
3323                         ushort mask = (1 << 4) - 1;
3324
3325                         // loop through right to left, shifting and looking up
3326                         // our value. Don't worry about negative
3327                         do {
3328                                 buffy[--position] = table[(value & mask)];
3329                                 value = (byte)(value >> 4);
3330                         } while (value != 0);
3331
3332                         // pad w/ 0's if they want more length, if not, ignore
3333                         precision -= (size - position);                         
3334                         while (precision > 0 && position > 1) {
3335                                 buffy[--position] = '0';
3336                                 precision--;
3337                         }
3338                         
3339                         return new string(buffy, position, (size - position));
3340                 }
3341
3342                 private static string FormatHexadecimal (short value, int precision, bool upper)
3343                 {
3344                         if (precision < 0) precision = 0;
3345                         int size = maxShortLength + precision;
3346                         char[] buffy = new char[size];
3347                         char[] table = upper ? digitUpperTable : digitLowerTable;
3348                         int position = size;
3349                         short mask = (1 << 4) - 1;
3350
3351                         // loop through right to left, shifting and looking up
3352                         // our value. If value is negavite stop after 4 F's
3353                         do {
3354                                 buffy[--position] = table[(value & mask)];
3355                                 value = (short)(value >> 4);
3356                         } while (value != 0 && position > (size - 4));
3357
3358                         // pad w/ 0's if they want more length, if not, ignore
3359                         precision -= (size - position);                         
3360                         while (precision > 0 && position > 1) {
3361                                 buffy[--position] = '0';
3362                                 precision--;
3363                         }
3364                         
3365                         return new string(buffy, position, (size - position));
3366                 }
3367
3368                 private static string FormatHexadecimal (int value, int precision, bool upper)
3369                 {
3370                         if (precision < 0) precision = 0;
3371                         int size = maxIntLength + precision;
3372                         char[] buffy = new char[size];
3373                         char[] table = upper ? digitUpperTable : digitLowerTable;
3374                         int position = size;
3375                         int mask = (1 << 4) - 1;
3376
3377                         // loop through right to left, shifting and looking up
3378                         // our value. If value is negavite stop after 8 F's
3379                         do {
3380                                 buffy[--position] = table[(value & mask)];
3381                                 value = value >> 4;
3382                         } while (value != 0 && position > (size - 8));
3383
3384                         // pad w/ 0's if they want more length, if not, ignore
3385                         precision -= (size - position);                         
3386                         while (precision > 0 && position > 1) {
3387                                 buffy[--position] = '0';
3388                                 precision--;
3389                         }
3390                         
3391                         return new string(buffy, position, (size - position));
3392                 }
3393
3394                 private static string FormatHexadecimal (long value, int precision, bool upper)
3395                 {
3396                         if (precision < 0) precision = 0;
3397                         int size = maxLongLength + precision;
3398                         char[] buffy = new char[size];
3399                         char[] table = upper ? digitUpperTable : digitLowerTable;
3400                         int position = size;
3401                         long mask = (1 << 4) - 1;
3402                         
3403                         // loop through right to left, shifting and looking up
3404                         // our value. If value is negavite stop after 16 F's
3405                         do {
3406                                 buffy[--position] = table[(value & mask)];
3407                                 value = value >> 4;
3408                         } while (value != 0 && position > (size - 16));
3409
3410                         // pad w/ 0's if they want more length, if not, ignore
3411                         precision -= (size - position);                         
3412                         while (precision > 0 && position > 1) {
3413                                 buffy[--position] = '0';
3414                                 precision--;
3415                         }
3416                         
3417                         return new string(buffy, position, (size - position));
3418                 }
3419
3420                 private static string FormatHexadecimal (sbyte value, int precision, bool upper)
3421                 {
3422                         if (precision < 0) precision = 0;
3423                         int size = maxByteLength + precision;
3424                         char[] buffy = new char[size];
3425                         char[] table = upper ? digitUpperTable : digitLowerTable;
3426                         int position = size;
3427                         short mask = (1 << 4) - 1;
3428
3429                         // loop through right to left, shifting and looking up
3430                         // our value. If value is negavite stop after 2 F's
3431                         do {
3432                                 buffy[--position] = table[(value & mask)];
3433                                 value = (sbyte)(value >> 4);
3434                         } while (value != 0 && position > (size - 2));
3435
3436                         // pad w/ 0's if they want more length, if not, ignore
3437                         precision -= (size - position);                         
3438                         while (precision > 0 && position > 1) {
3439                                 buffy[--position] = '0';
3440                                 precision--;
3441                         }
3442                         
3443                         return new string(buffy, position, (size - position));
3444                 }
3445
3446                 private static string FormatHexadecimal (ushort value, int precision, bool upper)
3447                 {                       
3448                         if (precision < 0) precision = 0;
3449                         int size = maxShortLength + precision;
3450                         char[] buffy = new char[size];
3451                         char[] table = upper ? digitUpperTable : digitLowerTable;
3452                         int position = size;
3453                         int mask = (1 << 4) - 1;
3454
3455                         // loop through right to left, shifting and looking up
3456                         // our value. Don't worry about negative
3457                         do {
3458                                 buffy[--position] = table[(value & mask)];
3459                                 value = (ushort)(value >> 4);
3460                         } while (value != 0);
3461
3462                         // pad w/ 0's if they want more length, if not, ignore
3463                         precision -= (size - position);                         
3464                         while (precision > 0 && position > 1) {
3465                                 buffy[--position] = '0';
3466                                 precision--;
3467                         }
3468                         
3469                         return new string(buffy, position, (size - position));
3470                 }
3471
3472                 private static string FormatHexadecimal (uint value, int precision, bool upper)
3473                 {                       
3474                         if (precision < 0) precision = 0;
3475                         int size = maxIntLength + precision;
3476                         char[] buffy = new char[size];
3477                         char[] table = upper ? digitUpperTable : digitLowerTable;
3478                         int position = size;
3479                         uint mask = (1 << 4) - 1;
3480
3481                         // loop through right to left, shifting and looking up
3482                         // our value. Don't worry about negative
3483                         do {
3484                                 buffy[--position] = table[(value & mask)];
3485                                 value = value >> 4;
3486                         } while (value != 0);
3487
3488                         // pad w/ 0's if they want more length, if not, ignore
3489                         precision -= (size - position);                         
3490                         while (precision > 0 && position > 1) {
3491                                 buffy[--position] = '0';
3492                                 precision--;
3493                         }
3494                         
3495                         return new string(buffy, position, (size - position));
3496                 }
3497
3498                 private static string FormatHexadecimal (ulong value, int precision, bool upper)
3499                 {                       
3500                         if (precision < 0) precision = 0;
3501                         int size = maxLongLength + precision;
3502                         char[] buffy = new char[size];
3503                         char[] table = upper ? digitUpperTable : digitLowerTable;
3504                         int position = size;
3505                         ulong mask = (1 << 4) - 1;
3506                         
3507                         // loop through right to left, shifting and looking up
3508                         // our value. Don't worry about negative
3509                         do {
3510                                 buffy[--position] = table[value & mask];
3511                                 value = value >> 4;
3512                         } while (value != 0);
3513                         
3514                         // pad w/ 0's if they want more length, if not, ignore
3515                         precision -= (size - position);
3516                         while (precision > 0 && position > 1) {
3517                                 buffy[--position] = '0';
3518                                 precision--;
3519                         }
3520
3521                         return new string(buffy, position, (size - position));
3522                 }
3523
3524                 // ============ Format Custom ============ //
3525
3526                 private static string FormatCustom (string format, sbyte number, NumberFormatInfo nfi)
3527                 {
3528                         string strnum = FormatGeneral (number, -1, nfi, true);
3529                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3530                         int sign = (number < 0) ? -1 : (number > 0) ? 1 : 0;
3531                         return fp.FormatNumber (strnum, sign);
3532                 }
3533
3534                 private static string FormatCustom (string format, short number, NumberFormatInfo nfi)
3535                 {
3536                         string strnum = FormatGeneral (number, -1, nfi, true);
3537                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3538                         int sign = (number < 0) ? -1 : (number > 0) ? 1 : 0;
3539                         return fp.FormatNumber (strnum, sign);
3540                 }
3541
3542                 private static string FormatCustom (string format, int number, NumberFormatInfo nfi)
3543                 {
3544                         string strnum = FormatGeneral (number, -1, nfi, true);
3545                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3546                         int sign = (number < 0) ? -1 : (number > 0) ? 1 : 0;
3547                         return fp.FormatNumber (strnum, sign);
3548                 }
3549
3550                 private static string FormatCustom (string format, long number, NumberFormatInfo nfi)
3551                 {
3552                         string strnum = FormatGeneral (number, -1, nfi, true);
3553                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3554                         int sign = (number < 0) ? -1 : (number > 0) ? 1 : 0;
3555                         return fp.FormatNumber (strnum, sign);
3556                 }
3557
3558                 private static string FormatCustom (string format, byte number, NumberFormatInfo nfi)
3559                 {
3560                         string strnum = FormatGeneral (number, -1, nfi, true);
3561                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3562                         return fp.FormatNumber (strnum, (number == 0) ? 0 : 1);
3563                 }
3564
3565                 private static string FormatCustom (string format, ushort number, NumberFormatInfo nfi)
3566                 {
3567                         string strnum = FormatGeneral (number, -1, nfi, true);
3568                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3569                         return fp.FormatNumber (strnum, (number == 0) ? 0 : 1);
3570                 }
3571
3572                 private static string FormatCustom (string format, uint number, NumberFormatInfo nfi)
3573                 {
3574                         string strnum = FormatGeneral (number, -1, nfi, true);
3575                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3576                         return fp.FormatNumber (strnum, (number == 0) ? 0 : 1);
3577                 }
3578
3579                 private static string FormatCustom (string format, ulong number, NumberFormatInfo nfi)
3580                 {
3581                         string strnum = FormatGeneral (number, -1, nfi, true);
3582                         FormatParse fp = new FormatParse (format); // FIXME: use nfi!
3583                         return fp.FormatNumber (strnum, (number == 0) ? 0 : 1);
3584                 }
3585         }
3586
3587 class FormatSection {
3588         public int nph;
3589         public int nphPreDot;
3590         public int npercent;
3591         public int ndividers;
3592         public int ntokens;
3593         public string [] tokens;
3594         public int [] TokenTypes;
3595         public bool HaveDot;
3596         public bool HaveSci;
3597         public bool sciSignAlways = false;
3598         public int sciDigits;
3599         public int numCommas;
3600 }
3601
3602 class FormatParse {
3603         const int AS_IS = 0;
3604         const int PH_0 = 1;
3605         const int PH_NUMBER = 2;
3606         const int COMMA = 3;
3607         const int PERCENT = 4;
3608         const int DIVIDERS = 5;
3609         const int DOT = 6;
3610         const int ESCAPE_SEQ = 7;
3611         const int SCIENTIFIC = 8;
3612         const int NEW_SECTION = 9;
3613         private FormatSection [] sections = new FormatSection[3];
3614         private int nsections = 0;
3615         private int pos; // Position in the format string
3616         private int group = 0; // Used in FormatPlain to insert a comma between groups of digits
3617         private bool isNegative;
3618
3619         private FormatParse ()
3620         {
3621         }
3622         
3623         public FormatParse (string format)
3624         {
3625                 parseFormat (format);
3626         }
3627
3628         private void FormatSci (char [] digits, ArrayList outputList, FormatSection sec)
3629         {
3630                 int tokidx = sec.ntokens - 1;
3631
3632                 // Output everything until we get to the SCIENTIFIC
3633                 while (tokidx >= 0 && sec.TokenTypes [tokidx] != SCIENTIFIC){
3634                         outputList.Add ((string) sec.tokens [tokidx--]);
3635                 }
3636
3637                 // Exponent
3638                 int exponent = digits.Length - sec.nph;
3639                 outputList.Add ((string) exponent.ToString ());
3640                 if (sec.sciSignAlways && exponent > 0)
3641                         outputList.Add ("+");
3642                 outputList.Add ((string) sec.tokens [tokidx--]);
3643
3644                 if (exponent < 0) {
3645                         char [] newDigits;
3646                         exponent = -exponent;
3647                         newDigits = new char [digits.Length + exponent];
3648                         Array.Copy (digits, 0, newDigits, exponent, digits.Length);
3649                         for (int i = 0; i < exponent; i++)
3650                                 newDigits[i] = '0';
3651                         digits = newDigits;
3652                 }
3653
3654                 // Now format the rest
3655                 int digitIdx = 0;
3656                 if (sec.HaveDot)
3657                         FormatDot (digits, ref digitIdx, outputList, sec, tokidx, 0);
3658                 else
3659                         FormatPlain (digits, ref digitIdx, outputList, sec, tokidx, 0, sec.numCommas > 0);
3660         }
3661
3662         private void FormatDot (char [] digits, ref int digitIdx, ArrayList outputList, 
3663                                 FormatSection sec, int lastToken, int firstToken)
3664         {
3665                 int tokidx = lastToken;
3666                 int type;
3667
3668                 while (tokidx >= firstToken) {
3669                         type = sec.TokenTypes [tokidx];
3670                         if (type == DOT || type == PH_NUMBER || type == PH_0)
3671                                 break;
3672                         tokidx--;
3673                 }
3674
3675                 if (tokidx > 0) {
3676                         char [] postDotDigits = new char [sec.nph - sec.nphPreDot];
3677                         int max = (postDotDigits.Length > digits.Length) ? digits.Length : postDotDigits.Length;
3678                         Array.Copy (digits, 0, postDotDigits, 0, max);
3679                         int postDotDigitsIdx = 0;
3680                         FormatPlain (postDotDigits, ref postDotDigitsIdx, outputList, sec, lastToken, tokidx, false);
3681                         tokidx--;
3682                         digitIdx += max;
3683                         FormatPlain (digits, ref digitIdx, outputList, sec, tokidx, 0, sec.numCommas > 0);
3684                 }
3685         }
3686
3687         private void FormatPlain (char [] digits, ref int digitIdx, ArrayList outputList, 
3688                                 FormatSection sec, int lastToken, int firstToken, bool insertComma)
3689         {
3690                 int tokidx = lastToken;
3691                 int type;
3692
3693                 while (tokidx >= firstToken) {
3694                         type = sec.TokenTypes [tokidx];
3695                         if (type == PH_0 || type == PH_NUMBER) {
3696                                 //FIXME: PH_NUMBER should also check for significant digits
3697                                 // Console.WriteLine ("group : {0}", group);
3698                                 int i = sec.tokens [tokidx].Length - 1;
3699                                 while (i >= 0) {
3700                                         if (insertComma && group == 3) {
3701                                                 outputList.Add (","); // FIXME: from NumberFormatInfo
3702                                                 group = 0;
3703                                         }
3704
3705                                         if (digitIdx < digits.Length)
3706                                                 outputList.Add ((string) digits[digitIdx++].ToString ());
3707                                         else
3708                                                 outputList.Add ("0");
3709                                         i--;
3710                                         if (insertComma)
3711                                                 group++;
3712                                         sec.nph--;
3713                                         while (sec.nph == 0 && digitIdx < digits.Length) {
3714                                                 // Flush the numbers left
3715                                                 if (insertComma && group == 3){
3716                                                         outputList.Add (","); // FIXME: from NumberFormatInfo
3717                                                         group = 0;
3718                                                 }
3719                                                 outputList.Add ((string) digits [digitIdx++].ToString ());
3720                                                 if (insertComma)
3721                                                         group++;
3722                                         }
3723
3724                                         if (sec.nph == 0 && isNegative)
3725                                                 outputList.Add ("-");
3726                                 }
3727                         } else {
3728                                 outputList.Add ((string) sec.tokens [tokidx]);
3729                         }
3730                         tokidx--;
3731                 }
3732
3733         }
3734
3735         private char [] AdjustDigits (string number, FormatSection sec)
3736         {
3737                 char [] digits = number.ToCharArray ();
3738                 char [] newDigits = digits;
3739                 int decPointIdx = 0;
3740                 int postDot = 0;
3741                 
3742                 decPointIdx -= sec.ndividers * 3;
3743                 decPointIdx += sec.npercent * 2;
3744                 if (sec.HaveDot){
3745                         postDot = sec.nph - sec.nphPreDot;
3746                         decPointIdx += postDot;
3747                 }
3748
3749                 if (decPointIdx > 0) {
3750                         newDigits = new char [digits.Length + decPointIdx];
3751                         Array.Copy (digits, 0, newDigits, 0, digits.Length);
3752                         for (int i = 0; i < decPointIdx; i++)
3753                                 newDigits[digits.Length + i] = '0';
3754                 } else if (decPointIdx < 0) {
3755                         decPointIdx = -decPointIdx;
3756                         if (decPointIdx >= digits.Length) {
3757                                 if (sec.HaveSci){
3758                                 } else {
3759                                         // The numbers turns into 0 when formatting applied
3760                                         digits = new char [1] {'0'};
3761                                 }
3762                         } else {
3763                                 int newLength = digits.Length - decPointIdx + postDot - 1;
3764                                 newDigits = new char [newLength];
3765                                 int max = digits.Length >= newLength ? newLength : digits.Length;
3766                                 Array.Copy (digits, 0, newDigits, 0, max);
3767                                 if (newLength > digits.Length)
3768                                         for (int i = 0; i < decPointIdx; i++)
3769                                                 newDigits[digits.Length + i] = '0';
3770                         }
3771                 }
3772
3773                 return newDigits;
3774         }
3775
3776         public string FormatNumber (string number, int signValue)
3777         {
3778                 char [] digits;
3779
3780                 isNegative = signValue < 0;
3781                 int section = 0;
3782                 if (signValue < 0 && nsections > 0)
3783                         section = 1;
3784                 if (signValue == 0 && nsections > 1)
3785                         section = 2;
3786
3787                 if (number [0] == '-')
3788                         number = number.Substring (1);
3789
3790                 FormatSection sec = sections [section];
3791                 digits = AdjustDigits (number.ToString (), sec);
3792                 if (digits.Length == 1 && digits [0] == '0')
3793                         if (nsections > 2)
3794                                 sec = sections [2]; // Format as a 0
3795                         else
3796                                 sec = sections [0]; // Format as positive
3797
3798                 ArrayList outputList = new ArrayList ();
3799
3800                 int digitIdx = 0;
3801                 Array.Reverse (digits);
3802
3803                 if (sec.HaveSci)
3804                         FormatSci (digits, outputList, sec);
3805                 else if (sec.HaveDot)
3806                         FormatDot (digits, ref digitIdx, outputList, sec, sec.ntokens - 1, 0);
3807                 else
3808                         FormatPlain (digits, ref digitIdx, outputList, sec, sec.ntokens - 1, 0, sec.numCommas > 0);
3809
3810                 string result = "";
3811                 for (int i = outputList.Count - 1; i >= 0; i--) {
3812                         result += (string) outputList[i];
3813                 }
3814
3815                 return result;
3816         }
3817
3818         private void parseFormat (string format)
3819         {
3820                 char [] fmt_chars = format.ToCharArray ();
3821                 int fmtlen = fmt_chars.Length;
3822                 int type = AS_IS;
3823                 int prevType = AS_IS;
3824                 string token;
3825
3826                 sections[0] = new FormatSection();
3827                 while (pos < fmtlen) {
3828
3829                         token = getNextToken (fmt_chars, fmtlen, out type);
3830                         if (type == NEW_SECTION) {
3831                                 nsections++;
3832                                 if (nsections > 3)
3833                                         break;
3834                                 sections[nsections] = new FormatSection();
3835                         } else {
3836                                 prevType = AddToken (token, type, prevType);
3837                         }                       
3838                 }
3839         }
3840
3841         private int AddToken (string token, int type, int prevType)
3842         {
3843                 FormatSection sec = sections[nsections];
3844                 string [] newTokens = new string [sec.ntokens + 1];
3845                 int [] newTokenTypes = new int [sec.ntokens + 1];
3846                 for (int i = 0; i < sec.ntokens; i++) {
3847                         newTokens[i] = sec.tokens[i];
3848                         newTokenTypes[i] = sec.TokenTypes[i];
3849                 }
3850
3851                 switch (type) {
3852                 case ESCAPE_SEQ :
3853                         type = AS_IS;
3854                         break;
3855                 case COMMA :
3856                         if (!sec.HaveDot && (prevType == PH_0 || prevType == PH_NUMBER)) {
3857                                 sec.numCommas++;
3858                         } else
3859                                 type = AS_IS;
3860
3861                         token = "";
3862                         break;
3863                 case DOT :
3864                         if (!sec.HaveDot && (prevType == PH_0 || prevType == PH_NUMBER ||
3865                             prevType == DIVIDERS || prevType == COMMA)) {
3866                                 sec.HaveDot = true;
3867                                 sec.nphPreDot = sec.nph;
3868                         } else
3869                                 type = AS_IS;
3870
3871                         break;
3872                 case PERCENT :
3873                         sec.npercent++;
3874                         break;
3875                 case DIVIDERS :
3876                         token = "";
3877                         if (!sec.HaveDot)
3878                                 sec.ndividers = token.Length;
3879                         else
3880                                 type = AS_IS;
3881                         break;
3882                 case PH_0 :
3883                         if (!sec.HaveSci)
3884                                 sec.nph += token.Length;
3885                         else
3886                                 type = AS_IS;
3887                         break;
3888                 case PH_NUMBER :
3889                         if (!sec.HaveSci)
3890                                 sec.nph += token.Length;
3891                         else
3892                                 type = AS_IS;
3893                         break;
3894                 case SCIENTIFIC :
3895                         if (!sec.HaveSci && sec.nph > 0) {
3896                                 sec.HaveSci = true;
3897                                 char [] sci = token.ToCharArray ();
3898                                 sec.sciSignAlways = sci[1] == '+' ? true : false;
3899                                 int expLen = sci[1] == '0' ? token.Length - 1 : token.Length - 2;
3900                                 sec.sciDigits = expLen;
3901                                 token = sci[0].ToString ();
3902                         } else {
3903                                 type = AS_IS;
3904                         }
3905                         break;
3906                 }
3907
3908                 newTokens[sec.ntokens] = token;
3909                 newTokenTypes[sec.ntokens] = type;
3910                 sec.tokens = newTokens;
3911                 sec.TokenTypes = newTokenTypes;
3912                 sec.ntokens++;
3913                 return type;
3914         }
3915         
3916         private string getNextToken (char [] fmt_chars, int fmtlen, out int type)
3917         {
3918                 int curpos = pos;
3919                 string result = null;
3920                 char current;
3921                 
3922                 type = AS_IS; // Default
3923                 current = fmt_chars[curpos];
3924                 if (current == ';'){
3925                         type = NEW_SECTION;
3926                         result = "NEW_SECTION";
3927                         pos++;
3928                 }
3929                 else if (current == '\'' || current == '"') {
3930                         char Quote = current;
3931                         curpos++;
3932                         int endpos = Array.IndexOf (fmt_chars, current, curpos);
3933                         if (endpos == -1)
3934                                 endpos = fmtlen;
3935                         result = new string (fmt_chars, curpos, endpos - curpos);
3936                         pos = endpos + 1;
3937                 } 
3938                 else if (current == '\\') { //MS seems not to translate escape seqs!
3939                         type = ESCAPE_SEQ;
3940                         current = fmt_chars[++pos];
3941                         result = current.ToString ();
3942                         pos++;
3943                 }
3944                 else if (current == '%') {
3945                         type = PERCENT;
3946                         result = "%";
3947                         pos++;
3948                 }
3949                 else if (current == '.') {
3950                         type = DOT;
3951                         result = ".";
3952                         pos++;
3953                 }
3954                 else if (current == ',') {
3955                         int begpos = curpos;
3956
3957                         while (++curpos < fmtlen && fmt_chars[curpos] == ',');
3958                         if (curpos == fmtlen || fmt_chars[curpos] == '.') {
3959                                 // ,,,,
3960                                 result = new string (fmt_chars, begpos, curpos - begpos);
3961                                 type = DIVIDERS;
3962                                 pos = curpos;
3963                         } else {
3964                                 result = ",";
3965                                 type = COMMA;
3966                                 pos++;
3967                         }
3968                 }
3969                 else if (current == '0' || current == '#') {
3970                         char placeHolder = current;
3971                         int begpos = curpos;
3972                         type = placeHolder == '0' ? PH_0 : PH_NUMBER;
3973                         curpos++;
3974                         while (curpos < fmtlen && fmt_chars [curpos] == placeHolder)
3975                                 curpos++;
3976                         result = new string (fmt_chars, begpos, curpos - begpos);
3977                         pos = curpos;
3978                 }
3979                 else if (current == 'e' || current == 'E') {
3980                         if (fmtlen <= curpos + 1){
3981                                 result = current.ToString ();
3982                                 pos++;
3983                         }
3984                         else {
3985                                 char next1 = fmt_chars [curpos + 1];
3986
3987                                 if (next1 != '-' && next1 != '+' && next1 != '0') {
3988                                         result = new string (fmt_chars, curpos, 2);
3989                                         pos += 2;
3990                                 }
3991                                 else {
3992                                         int begpos = curpos;
3993
3994                                         if (next1 == '-' || next1 == '+')
3995                                                 curpos++;
3996
3997                                         curpos++;
3998
3999                                         if (curpos < fmtlen && fmt_chars [curpos] == '0'){
4000                                                 type = SCIENTIFIC;
4001                                                 while (curpos < fmtlen && fmt_chars [curpos] == '0')
4002                                                         curpos++;
4003                                         }
4004
4005                                         result = new string (fmt_chars, begpos, curpos - begpos);
4006                                         pos = curpos;
4007                                 }
4008                         }
4009                 }
4010                 else {
4011                         char [] format_spec = { '0', '#', ',', '.', '%', 'E', 'e', '"', '\'', '\\' };
4012                         int nextFE;
4013
4014                         while (curpos < fmtlen) {
4015                                 current = fmt_chars[curpos];
4016                                 nextFE = Array.IndexOf (format_spec, current);
4017                                 if (nextFE != -1)
4018                                         break;
4019                                 curpos++;
4020                         }
4021
4022                         result = new string (fmt_chars, pos, curpos - pos);
4023                         pos = curpos;
4024                 }
4025
4026                 return result;
4027         }
4028 }
4029
4030 }