00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 module mango.convert.Format;
00041
00042 private import std.stdarg;
00043
00044 private import mango.convert.Type,
00045 mango.convert.Integer;
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 struct FormatStructTemplate(T)
00056 {
00057 private alias IntegerTemplate!(T) Integer;
00058
00059 private alias Integer.Flags Flags;
00060
00061 typedef T[] function (T[], double, uint, bool) DblFormat;
00062
00063 typedef uint delegate (void[], uint type) Emitter;
00064
00065 typedef void delegate () Close;
00066
00067
00068 private Emitter sink;
00069 private Close close;
00070 private int style,
00071 width,
00072 precision;
00073 private Flags flags;
00074 private T[] head,
00075 tail,
00076 meta;
00077 private DblFormat dFormat;
00078 private T[] workspace;
00079
00080
00081 private static T[64] Spaces = ' ';
00082
00083 mixin Type.TextType!(T);
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 private static ubyte DefaultStyle[] = ['s', 'd', 'u', 'd', 'u',
00095 'd', 'u', 'd', 'u', 'f',
00096 'f', 'f', 's', 's', 's',
00097 'x'];
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 void ctor (Emitter sink, Close close, T[] workspace, DblFormat dFormat = null)
00109 {
00110 this.sink = sink;
00111 this.close = close;
00112 this.dFormat = dFormat;
00113 this.workspace = workspace;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122 static void error (char[] msg)
00123 {
00124 Integer.error(msg);
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 int opCall (T[] format, TypeInfo[] arguments, va_list argptr)
00145 {
00146 int length;
00147
00148
00149 meta = format;
00150
00151
00152 foreach (TypeInfo ti; arguments)
00153 {
00154 int count = 1;
00155 void *p = argptr;
00156
00157 uint t = ti.classinfo.name[9];
00158
00159
00160 if (t == 'A')
00161 {
00162 t = ti.classinfo.name[10];
00163 p = (*(cast(void[]*) argptr)).ptr;
00164 count = (*(cast(void[]*) argptr)).length;
00165 }
00166
00167 t = getType (t);
00168 int width = Type.widths[t];
00169
00170
00171 length += emit (p, width * count, t);
00172
00173
00174 argptr += (count > 1) ? (void[]).sizeof : ((width + int.sizeof - 1) & ~(int.sizeof - 1));
00175 }
00176
00177
00178 if (meta.length)
00179 {
00180 length += sink (meta, TextType);
00181 meta = null;
00182 }
00183
00184 if (close)
00185 close();
00186
00187 return length;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197 int opCall (T[] format, void* src, uint bytes, uint type)
00198 {
00199 meta = format;
00200 int length = emit (src, bytes, type);
00201
00202
00203 if (meta.length)
00204 {
00205 length += sink (meta, TextType);
00206 meta = null;
00207 }
00208 return length;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 int emit (void* src, uint bytes, uint type)
00233 {
00234 int iValue;
00235 long lValue;
00236 double fValue;
00237 uint length;
00238
00239
00240 if (parse (meta) == 0)
00241 style = DefaultStyle[type];
00242
00243 if (flags & Flags.Array)
00244 meta = null;
00245 else
00246 {
00247
00248 meta = tail;
00249 tail = null;
00250 }
00251
00252
00253 int size = Type.widths[type];
00254
00255
00256 if (head.length)
00257 length = sink (head, TextType);
00258
00259
00260 while (bytes)
00261 {
00262 switch (type)
00263 {
00264 case Type.Bool:
00265 iValue = *cast(bool*) src;
00266 if (style != 's')
00267 goto int32Format;
00268
00269 static T[] True = "true",
00270 False = "false";
00271
00272 length += sink (iValue ? True : False, TextType);
00273 break;
00274
00275 case Type.Byte:
00276 iValue = *cast(byte*) src;
00277 goto int32Format;
00278
00279 case Type.UByte:
00280 iValue = *cast(ubyte*) src;
00281 goto int32Format;
00282
00283 case Type.Short:
00284 iValue = *cast(short*) src;
00285 goto int32Format;
00286
00287 case Type.UShort:
00288 iValue = *cast(ushort*) src;
00289 goto int32Format;
00290
00291 case Type.Int:
00292 case Type.UInt:
00293 case Type.Pointer:
00294 int32:
00295 iValue = *cast(int*) src;
00296 int32Format:
00297 length += emit (cast(long) iValue);
00298 break;
00299
00300 case Type.Long:
00301 case Type.ULong:
00302 int64:
00303 lValue = *cast(long*) src;
00304 int64Format:
00305 length += emit (lValue);
00306 break;
00307
00308 case Type.Float:
00309 if (style == 'x' ||
00310 style == 'X')
00311 goto int32;
00312 fValue = *cast(float*) src;
00313 goto floating;
00314
00315 case Type.Double:
00316 if (style == 'x' ||
00317 style == 'X')
00318 goto int64;
00319 fValue = *cast(double*) src;
00320 floating:
00321 length += emit (fValue);
00322 break;
00323
00324 case Type.Real:
00325 fValue = *cast(real*) src;
00326 goto floating;
00327
00328 case Type.Utf8:
00329 case Type.Utf16:
00330 case Type.Utf32:
00331
00332 int len = bytes;
00333 if (style == 's')
00334 {
00335
00336 if (flags & Flags.Prec)
00337 if (precision < len)
00338 len = precision;
00339 bytes = size;
00340 }
00341 else
00342 if (style == 'c')
00343
00344 len = size;
00345 else
00346 {
00347
00348 if (type == Type.Utf16)
00349 type = Type.UShort;
00350 else
00351 if (type == Type.Utf32)
00352 type = Type.UInt;
00353 else
00354 type = Type.UByte;
00355 continue;
00356 }
00357
00358
00359 length += emit (src[0..len], type);
00360 break;
00361
00362 default:
00363 Integer.error ("Format.emit : unexpected argument type");
00364 }
00365
00366
00367 bytes -= size;
00368 src += size;
00369 }
00370 return length;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380 private static uint getType (uint t)
00381 {
00382 static ubyte xlate[] =
00383 [
00384 Type.Utf8, Type.Bool, 0, Type.Double, Type.Real,
00385 Type.Float, Type.Byte, Type.UByte, Type.Int, 0,
00386 Type.UInt, Type.Long, Type.ULong, 0, 0, 0, 0, 0,
00387 Type.Short, Type.UShort, Type.Utf16, 0, Type.Utf32,
00388 ];
00389
00390 if (t >= 'a' && t <= 'w')
00391 t = xlate[t - 'a'];
00392 else
00393 if (t == 'P')
00394 t = Type.Pointer;
00395 else
00396 Integer.error ("Format.getType : unexpected argument type");
00397 return t;
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407 private void reset ()
00408 {
00409 flags = 0;
00410 head = tail = null;
00411 width = workspace.length;
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 private int spaces (int count)
00424 {
00425 int ret;
00426
00427 while (count > Spaces.length)
00428 {
00429 ret += sink (Spaces, TextType);
00430 count -= Spaces.length;
00431 }
00432 return ret + sink (Spaces[0..count], TextType);
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
00442 private int emit (void[] field, int type = TextType)
00443 {
00444 int i = 0;
00445 int pad = 0;
00446
00447
00448
00449
00450
00451
00452 if (flags & Flags.Fill && flags & Flags.Space)
00453 {
00454 pad = width - field.length;
00455 if (pad < 0)
00456 pad = 0;
00457
00458
00459 if ((flags & Flags.Left) == 0)
00460 {
00461 i += spaces (pad);
00462 pad = 0;
00463 }
00464 }
00465
00466
00467 i += sink (field, type);
00468
00469
00470 if (pad)
00471 i += spaces (pad);
00472
00473
00474 if (tail.length)
00475 i += sink (tail, TextType);
00476
00477 return i;
00478 }
00479
00480
00481
00482
00483
00484
00485
00486 private int emit (long field)
00487 {
00488 return emit (Integer.format (workspace[0..width], field,
00489 cast(Integer.Format) style, flags));
00490 }
00491
00492
00493
00494
00495
00496
00497
00498 private int emit (double field)
00499 {
00500 if (dFormat == null)
00501 Integer.error ("Format.emit : decimal formatting not configured");
00502
00503 return emit (dFormat (workspace, field,
00504 (flags & Flags.Prec) ? precision : 6,
00505 cast(bool) (style == 'e')));
00506 }
00507
00508
00509
00510
00511
00512
00513
00514 private static final bool isDigit (T t)
00515 {
00516 return cast(bool) (t >= '0' && t <= '9');
00517 }
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 private T parse (T[] format)
00568 {
00569 reset ();
00570 head = format;
00571 T* p = format.ptr;
00572
00573 for (int i = format.length; --i > 0; ++p)
00574 if (*p == '%')
00575 if (p[1] == '%')
00576 ++p;
00577 else
00578 {
00579 int len = p - format.ptr;
00580 head = format [0..len];
00581 while (1)
00582 {
00583 switch (--i, *++p)
00584 {
00585 case '-':
00586 flags |= Flags.Left;
00587 continue;
00588
00589 case '+':
00590 flags |= Flags.Plus;
00591 continue;
00592
00593 case '#':
00594 flags |= Flags.Hash;
00595 continue;
00596
00597 case ' ':
00598 flags |= Flags.Space;
00599 continue;
00600
00601 case '0':
00602 flags |= Flags.Zero;
00603 continue;
00604
00605 case '@':
00606 flags |= Flags.Array;
00607 continue;
00608
00609 default:
00610 ++i;
00611 break;
00612 }
00613 break;
00614 }
00615
00616 if (isDigit(*p))
00617 {
00618 int tmp;
00619 do {
00620 tmp = tmp * 10 + (*p - '0');
00621 } while (--i && isDigit(*++p));
00622
00623 flags |= Flags.Fill;
00624 width = tmp;
00625 }
00626 else
00627 flags &= ~Flags.Zero;
00628
00629
00630 if (*p == '.')
00631 {
00632 int tmp;
00633 while (i-- && isDigit(*++p))
00634 tmp = tmp * 10 + (*p - '0');
00635
00636 flags |= Flags.Prec;
00637 precision = tmp;
00638 }
00639
00640 if (--i < 0)
00641 Integer.error ("Format.parse : missing format specifier");
00642
00643 tail = format [format.length-i..format.length];
00644 return style = *p;
00645 }
00646
00647 return style = 0;
00648 }
00649 }
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659 alias FormatStructTemplate!(char) FormatStruct;
00660
00661
00662
00663
00664
00665
00666 class FormatClassTemplate(T)
00667 {
00668 alias FormatStructTemplate!(T) Format;
00669
00670 private T[128] tmp;
00671 private Format format;
00672
00673
00674
00675
00676
00677 this (Format.Emitter sink, Format.Close close, Format.DblFormat df = null)
00678 {
00679 format.ctor (sink, close, tmp, df);
00680 }
00681
00682
00683
00684
00685
00686 int opCall (T[] fmt, ...)
00687 {
00688 return format (fmt, _arguments, _argptr);
00689 }
00690 }
00691
00692
00693 alias FormatClassTemplate!(char) Format;