Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Format.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file Format.d
00004         
00005         Copyright (c) 2004 Kris Bell
00006         
00007         This software is provided 'as-is', without any express or implied
00008         warranty. In no event will the authors be held liable for damages
00009         of any kind arising from the use of this software.
00010         
00011         Permission is hereby granted to anyone to use this software for any 
00012         purpose, including commercial applications, and to alter it and/or 
00013         redistribute it freely, subject to the following restrictions:
00014         
00015         1. The origin of this software must not be misrepresented; you must 
00016            not claim that you wrote the original software. If you use this 
00017            software in a product, an acknowledgment within documentation of 
00018            said product would be appreciated but is not required.
00019 
00020         2. Altered source versions must be plainly marked as such, and must 
00021            not be misrepresented as being the original software.
00022 
00023         3. This notice may not be removed or altered from any distribution
00024            of the source.
00025 
00026         4. Derivative works are permitted, but they must carry this notice
00027            in full and credit the original source.
00028 
00029 
00030                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00031 
00032         
00033         @version        Initial version; April 2005
00034 
00035         @author         Kris
00036 
00037 
00038 *******************************************************************************/
00039 
00040 module mango.format.Format;
00041 
00042 private import  mango.sys.Type;
00043 
00044 private import  mango.format.Int,
00045                 mango.format.Long,
00046                 mango.format.Styled;
00047 
00048 /******************************************************************************
00049 
00050         Utility functions for styled, readable, output.
00051 
00052         While these functions are all static, they are encapsulated within 
00053         a class inheritance to preserve some namespace cohesion. One might 
00054         use structs for encapsualtion instead, but then inheritance would 
00055         be lost. Note that the root class, Styled, is abstract to prevent 
00056         accidental instantiation of these classes.
00057 
00058         See Styled.parse() for the list of format specifiers.
00059 
00060 ******************************************************************************/
00061 
00062 class Format : Styled
00063 {       
00064         /**********************************************************************
00065 
00066                 Default styles for supported types. This is used to 
00067                 format discrete values, or those provided without a 
00068                 specified format-string. 
00069 
00070         **********************************************************************/
00071 
00072         static ubyte DefaultStyle[] = [
00073                                       's', 'd', 'u', 'd', 'u', 
00074                                       'd', 'u', 'd', 'u', 'f', 
00075                                       'f', 'f', 's', 's', 's', 
00076                                       'x'
00077                                       ];
00078 
00079 
00080         /**********************************************************************
00081 
00082                 Equivalent to vsprintf(). State is maintained on the
00083                 stack only, making this thread-safe. You may supply
00084                 a workspace buffer as an optional initialization arg,
00085                 which should typically also be allocated on the stack.
00086 
00087                 See Styled.parse() for the list of format specifiers.
00088 
00089         **********************************************************************/
00090 
00091         protected struct Sprintf
00092         {
00093                 Style           style;
00094                 char[80]        local;
00095                 char[]          buffer;
00096                 char*           p, limit;
00097 
00098                 void opCall (char[] dst, char[] workspace = null, DblFormat df = null)
00099                 {
00100                         style (&utf8, workspace.length ? workspace : local, df);
00101                         p = buffer = dst;
00102                         limit = p + buffer.length;
00103                 }
00104 
00105                 int utf8 (char[] s)
00106                 {
00107                         int len = s.length;
00108                         if (p+len < limit)
00109                            {
00110                            p[0..len] = s[0..len];
00111                            p += len;       
00112                            return len;
00113                            }
00114                         error ("Sprintf overflow");
00115                 }
00116 
00117                 int format (char[] fmt, ...)
00118                 {
00119                         style.setFormat (fmt);
00120                         return print (style, _arguments, _argptr);
00121                 }
00122 
00123                 int format (char[] fmt, TypeInfo[] ti, void* args)
00124                 {
00125                         style.setFormat (fmt);
00126                         return print (style, ti, args);
00127                 }
00128         }
00129 
00130         /***********************************************************************
00131         
00132                 General purpose va_arg format routine, used by a number of
00133                 classes and structs to emit printf() styled text. 
00134 
00135                 This implementation simply converts its arguments into the
00136                 appropriate internal type, and invokes the standard Mango
00137                 type-formatter for each.
00138 
00139                 Note that this can handle type-arrays in addition to the
00140                 usual char[] ~ e.g. one can print an array of integers just
00141                 as easily as a single integer.
00142 
00143                 See Styled.parse() for the list of format specifiers.
00144 
00145         ***********************************************************************/
00146 
00147         static int print (inout Style style, TypeInfo[] arguments, void* argptr)
00148         {      
00149                 // internal method to map data types 
00150                 uint getType (uint type)
00151                 {
00152                         static  ubyte xlate[] = 
00153                                 [
00154                                 Type.Utf8, Type.Bool, 0, Type.Double, Type.Real, 
00155                                 Type.Float, Type.Byte, Type.UByte, Type.Int, 0, 
00156                                 Type.UInt, Type.Long, Type.ULong, 0, 0, 0, 0, 0, 
00157                                 Type.Short, Type.UShort, Type.Utf16, 0, Type.Utf32, 
00158                                 ];
00159 
00160                         if (type >= 'a' && type <= 'w')
00161                             type = xlate[type - 'a'];
00162                         else
00163                            if (type == 'P')
00164                                type = Type.Pointer;
00165                            else
00166                               error ("unknown type handed to Format.print()");
00167                         return type;
00168                 }
00169 
00170 
00171                 int length;
00172 
00173                 // loop over each argument ...
00174                 foreach (TypeInfo ti; arguments)
00175                         {
00176                         int count = 1;
00177                         void *p = argptr;
00178 
00179                         uint type = ti.classinfo.name[9];
00180 
00181                         // is this an array type?
00182                         if (type == 'A')
00183                            {
00184                            type = ti.classinfo.name[10];
00185                            p = (*(cast(void[]*) argptr)).ptr;
00186                            count = (*(cast(void[]*) argptr)).length;
00187                            }                
00188 
00189                         type = getType (type);
00190                         int width = Type.widths[type];
00191                         length += print (style, p, width * count, type);
00192 
00193                         argptr += (count > 1) ? (void[]).sizeof : ((width + int.sizeof - 1) & ~(int.sizeof - 1));
00194                         }
00195 
00196                 // flush any remaining format text
00197                 if (style.meta.length)
00198                    {
00199                    length += style.utf8 (style.meta);
00200                    style.meta = null;
00201                    }
00202 
00203                 return length;
00204         }
00205 
00206 
00207         /***********************************************************************
00208         
00209                 Convert various types into textual representation. This 
00210                 is used by DisplayWriter/PrintWriter, and by the various
00211                 users of the variadic-argument functions.
00212 
00213                 See print() above, along with the DisplayWriter class.
00214 
00215                 Note that print() can handle type-arrays in addition to the
00216                 usual char[]; e.g. one can print an array of integers just
00217                 as easily as a single integer. To support this, a new style
00218                 flag has been introduced to terminate the format string at
00219                 the point of use. That is, the rest of the format string is
00220                 considered to be part of the current format specifier, and
00221                 will be repeated for each array element. For example, the
00222                 format string " %@x," has a preceeding space, a trailing
00223                 comma, and the array flag '@'. This will output an array of 
00224                 numeric values (char, byte, short, int, long, float, double,
00225                 real, pointer) as a set of formatted hexadecimal strings.
00226 
00227                 See Styled.parse() for the list of format specifiers.
00228 
00229         ***********************************************************************/
00230 
00231         static int print (inout Style style, void* src, uint bytes, uint type)
00232         {
00233                 uint    iValue;
00234                 ulong   lValue;
00235                 double  fValue;
00236                 uint    length;
00237 
00238                 // convert format segment to Style
00239                 if (style.parse (style.meta) == 0)
00240                     style.type = DefaultStyle[type];
00241 
00242                 if (style.flags & Flags.Array)
00243                     style.meta = null;
00244                 else
00245                    {
00246                    // flip remaining format, if array not specified
00247                    style.meta = style.tail;
00248                    style.tail = null;
00249                    }
00250 
00251                 // get width of elements (note: does not work for bit[])
00252                 int width = Type.widths[type];
00253 
00254                 // for all bytes in source ...
00255                 while (bytes)
00256                       {
00257                       switch (type)
00258                              {
00259                              case Type.Bool:
00260                                   iValue = *cast(bool*) src;
00261                                   if (style.type != 's')
00262                                       goto int32Format;
00263                                   length += style.utf8 (iValue ? "true" : "false");
00264                                   break;
00265 
00266                              case Type.Byte:
00267                                   iValue = *cast(byte*) src;
00268                                   goto int32Format;
00269 
00270                              case Type.UByte:
00271                                   iValue = *cast(ubyte*) src;
00272                                   goto int32Format;
00273 
00274                              case Type.Short:
00275                                   iValue = *cast(short*) src;
00276                                   goto int32Format;
00277 
00278                              case Type.UShort:
00279                                   iValue = *cast(ushort*) src;
00280                                   goto int32Format;
00281 
00282                              case Type.Int:
00283                              case Type.UInt:
00284                              case Type.Pointer:
00285 int32:
00286                                   iValue = *cast(uint*) src;
00287 int32Format:
00288                                   length += Int.format (iValue, style);
00289                                   break;
00290 
00291                              case Type.Long:
00292                              case Type.ULong:
00293 int64:
00294                                   lValue = *cast(ulong*) src;
00295 int64Format:
00296                                   length += Long.format (lValue, style);
00297                                   break;
00298 
00299                              case Type.Float:
00300                                   if (style.type == 'x' || 
00301                                       style.type == 'X')
00302                                       goto int32;
00303                                   fValue = *cast(float*) src;
00304                                   goto floating;
00305 
00306                              case Type.Double:
00307                                   if (style.type == 'x' || 
00308                                       style.type == 'X')
00309                                       goto int64;
00310                                   fValue = *cast(double*) src;
00311 floating:
00312                                   if (style.dFormat == null)
00313                                       error ("floating point formatting not configured");
00314                                   length += style.dFormat (fValue, style);
00315                                   break;
00316 
00317                              case Type.Real:
00318                                   fValue = *cast(real*) src;
00319                                   goto floating;
00320 
00321                              case Type.Utf8:
00322                                   char[] s;
00323                                   if (style.type == 's')
00324                                      {
00325                                      int len = bytes;
00326                                      if (style.flags & Flags.Prec)
00327                                          if (style.precision < len)
00328                                              len = style.precision;
00329                                      s = cast(char[]) src[0..len];
00330                                      bytes = 1;
00331                                      }
00332                                   else
00333                                      if (style.type == 'c')
00334                                          s = cast(char[]) src[0..1];
00335                                      else
00336                                         {
00337                                         type = Type.UByte;
00338                                         continue;
00339                                         }
00340                                   length += style.emit (s);
00341                                   break;
00342 
00343                              default:
00344                                   error ("unknown type handed to Format.print()");
00345                              }
00346 
00347                       // bump counters and loop around for next instance
00348                       bytes -= width;
00349                       src += width;
00350                       }
00351                 return length;
00352         }
00353 }

Generated on Fri Nov 11 18:44:19 2005 for Mango by  doxygen 1.4.0