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
00032 #include "common.h"
00033 #include "stringf.h"
00034
00035
00036
00037
00038
00039
00040
00041 longlong StringFormatter::ConversionSpec::GetIntArg(unsigned flags)
00042 {
00043 va_list& args = Args;
00044 if(flags&LengthMod_ll)
00045 return va_arg(args,ulonglong);
00046
00047 if(flags&LengthMod_l)
00048 {
00049
00050 unsigned long int val = va_arg(args,unsigned long int);
00051 if(flags&SignedInt)
00052 return (signed long int)val;
00053 else
00054 return val;
00055 }
00056
00057
00058
00059 unsigned val = va_arg(args,unsigned int);
00060
00061
00062 if(flags&LengthMod_h)
00063 {
00064 if(flags&SignedInt)
00065 return (signed short int)val;
00066 else
00067 return (unsigned short int)val;
00068 }
00069 else if(flags&LengthMod_hh)
00070 {
00071 if(flags&SignedInt)
00072 return (signed char)val;
00073 else
00074 return (unsigned char)val;
00075 }
00076 else
00077 {
00078 if(flags&SignedInt)
00079 return (signed int)val;
00080 else
00081 return val;
00082 }
00083 }
00084
00085
00086 const char* StringFormatter::ConversionSpec::ReadInt(const char* format, int& val)
00087 {
00088 unsigned c = *format++;
00089 if(c=='*')
00090 {
00091 val = GetIntArg();
00092 return format;
00093 }
00094
00095
00096 unsigned v = 0;
00097 for(;;)
00098 {
00099 c -= '0';
00100 if(c>=10u)
00101 break;
00102 v = v*10+c;
00103 c = *format++;
00104 }
00105 --format;
00106 val = v;
00107 return format;
00108 }
00109
00110
00111 const char* StringFormatter::ConversionSpec::Decode(const char* format)
00112 {
00113 char c;
00114
00115
00116 unsigned flags = 0;
00117 for(;;)
00118 {
00119 c = *format++;
00120 if(c=='-')
00121 flags |= FlagMinus;
00122 else if(c=='+')
00123 flags |= FlagPlus;
00124 else if(c==' ')
00125 flags |= FlagSpace;
00126 else if(c=='#')
00127 flags |= FlagHash;
00128 else if(c=='0')
00129 flags |= FlagZero;
00130 else
00131 break;
00132 }
00133 --format;
00134
00135
00136 format = ReadInt(format,FieldWidth);
00137 if(FieldWidth<0)
00138 {
00139 FieldWidth = -FieldWidth;
00140 flags |= FlagMinus;
00141 }
00142
00143
00144 Precision = -1;
00145 if(*format=='.')
00146 {
00147 ++format;
00148 format = ReadInt(format,Precision);
00149 }
00150
00151
00152 #define LENGTH_MODIFIER(type) \
00153 ( \
00154 sizeof(type)==sizeof(char)?LengthMod_hh : \
00155 sizeof(type)==sizeof(short)?LengthMod_h : \
00156 sizeof(type)==sizeof(int)?0 : \
00157 sizeof(type)==sizeof(long)?LengthMod_l : \
00158 sizeof(type)==sizeof(longlong)?LengthMod_ll : \
00159 LengthMod_unknown \
00160 )
00161
00162 c = *format++;
00163 if(c=='h')
00164 {
00165 if(*format!=c)
00166 flags |= LengthMod_h;
00167 else
00168 {
00169 flags |= LengthMod_hh;
00170 ++format;
00171 }
00172 }
00173 else if(c=='l')
00174 {
00175 if(*format!=c)
00176 flags |= LengthMod_l;
00177 else
00178 {
00179 flags |= LengthMod_ll;
00180 ++format;
00181 }
00182 }
00183 else if(c=='L')
00184 flags |= LengthMod_L;
00185 else if(c=='j')
00186 {
00187 flags |= LENGTH_MODIFIER(intmax_t);
00188 ASSERT_COMPILE(LENGTH_MODIFIER(intmax_t)!=LengthMod_unknown);
00189 }
00190 else if(c=='z')
00191 {
00192 flags |= LENGTH_MODIFIER(size_t);
00193 ASSERT_COMPILE(LENGTH_MODIFIER(size_t)!=LengthMod_unknown);
00194 }
00195 else if(c=='t')
00196 {
00197 flags |= LENGTH_MODIFIER(ptrdiff_t);
00198 ASSERT_COMPILE(LENGTH_MODIFIER(ptrdiff_t)!=LengthMod_unknown);
00199 }
00200 else
00201 --format;
00202
00203
00204 if(flags&FlagMinus)
00205 flags &= ~FlagZero;
00206 Flags = flags;
00207
00208
00209 c = *format++;
00210 ConversionSpecifier = c;
00211 if(!c)
00212 --format;
00213 return format;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 char* StringFormatter::PushHex(ulonglong val, char* dst, int precision, int x, int prefix)
00223 {
00224 if(!val)
00225 {
00226
00227 prefix = false;
00228 if(!precision)
00229 return dst;
00230 }
00231
00232 if(precision<0)
00233 precision = 1;
00234
00235 int alphaAdjust = x-'X'+7;
00236 do
00237 {
00238 unsigned c = val&0xf;
00239 if(c>=10)
00240 c += alphaAdjust;
00241 c += '0';
00242 *--dst = c;
00243 --precision;
00244 val >>= 4;
00245 }
00246 while(val);
00247
00248 while(--precision>=0)
00249 *--dst = '0';
00250
00251 if(prefix)
00252 {
00253 *--dst = x;
00254 *--dst = '0';
00255 }
00256
00257 return dst;
00258 }
00259
00260
00261 char* StringFormatter::PushOctal(ulonglong val, char* dst, int precision, int prefix)
00262 {
00263 if(!precision && !val)
00264 return dst;
00265
00266 if(precision<0)
00267 precision = 1;
00268
00269 do
00270 {
00271 unsigned c = val&0x7;
00272 c += '0';
00273 *--dst = c;
00274 --precision;
00275 val >>= 3;
00276 }
00277 while(val);
00278
00279 while(--precision>=0)
00280 *--dst = '0';
00281
00282 if(prefix && *dst!='0')
00283 *--dst = '0';
00284
00285 return dst;
00286 }
00287
00288
00289 char* StringFormatter::PushDecimal(ulonglong val, char* dst, int precision)
00290 {
00291 if(!precision && !val)
00292 return dst;
00293
00294 if(precision<0)
00295 precision = 1;
00296
00297 if(val<=0xffffffffu)
00298 {
00299
00300 unsigned a = (unsigned)val;
00301 while(a)
00302 {
00303
00304
00305
00306 unsigned q = a>>1;
00307 q += q>>1;
00308 q += q>>4;
00309 q += q>>8;
00310 q += q>>16;
00311 q = q>>3;
00312
00313
00314
00315 unsigned r = a - q*10;
00316 if(r>=10)
00317 {
00318
00319 r -= 10;
00320 ++q;
00321 }
00322 a = q;
00323
00324 *--dst = r+'0';
00325 --precision;
00326 }
00327 }
00328 else
00329 {
00330
00331 ulonglong a = val;
00332 do
00333 {
00334
00335
00336
00337 ulonglong q = a>>1;
00338 q += q>>1;
00339 q += q>>4;
00340 q += q>>8;
00341 q += q>>16;
00342 q += (q>>32);
00343 q += ((q>>32)>>32);
00344 ASSERT_COMPILE(sizeof(ulonglong)<=sizeof(uint64_t)*2);
00345 q = q>>3;
00346
00347
00348
00349 unsigned r = a - q*10;
00350 if(r>=10)
00351 {
00352
00353 r -= 10;
00354 ++q;
00355 }
00356 a = q;
00357
00358 *--dst = r+'0';
00359 --precision;
00360 }
00361 while(a);
00362 }
00363
00364 while(--precision>=0)
00365 *--dst = '0';
00366
00367 return dst;
00368 }
00369
00370
00371
00372 char* StringFormatter::DefaultUnkownFormat(char*& dstEnd, ConversionSpec& spec)
00373 {
00374 char c = spec.ConversionSpecifier;
00375
00376
00377 if(c>='A' && c<='Z')
00378 c += 'a'-'A';
00379 if(c=='a' || c=='e' || c=='f' || c=='g')
00380 {
00381
00382 if(spec.Flags&LengthMod_L)
00383 va_arg(spec.Args,long double);
00384 else
00385 va_arg(spec.Args,double);
00386 return dstEnd;
00387 }
00388
00389
00390 return dstEnd;
00391 }
00392
00393
00394
00395 #ifndef STRINGFORMATTER_UNKOWNFORMAT_DEFINED
00396
00397 char* StringFormatter::UnkownFormat(char*& dstEnd, ConversionSpec& format)
00398 {
00399 return DefaultUnkownFormat(dstEnd, format);
00400 }
00401
00402 #endif
00403
00404
00405 size_t StringFormatter::VFormat(const char* formatString, va_list args)
00406 {
00407 ConversionSpec convertionSpec(args);
00408
00409 size_t outSize = 0;
00410 const char* src = formatString;
00411 for(;;)
00412 {
00413 char c;
00414
00415
00416 const char* srcBase = src;
00417 do c = *src++;
00418 while(c!=0 && c!='%');
00419
00420
00421 size_t size = src-srcBase-1;
00422 outSize += size;
00423 Out(srcBase,size);
00424
00425 if(c==0)
00426 {
00427
00428 return outSize;
00429 }
00430
00431 if(*src=='%')
00432 {
00433
00434 ++outSize;
00435 Out(src++,1);
00436 continue;
00437 }
00438
00439
00440 src = convertionSpec.Decode(src);
00441
00442
00443 char temp[FormatTextBufferSize];
00444 ASSERT_COMPILE(FormatTextBufferSize>sizeof(longlong)/2*5+1);
00445 ASSERT_COMPILE(FormatTextBufferSize>(sizeof(longlong)*8+2)/3+1);
00446 ASSERT_COMPILE(FormatTextBufferSize>(sizeof(longlong)*2)+2);
00447 char* stringEnd = temp+sizeof(temp);
00448 register char* string = stringEnd;
00449 size_t zeroPadPosition = 0;
00450 unsigned flags = convertionSpec.Flags;
00451
00452
00453 c = convertionSpec.ConversionSpecifier;
00454 if(c=='c')
00455 {
00456 *--string = (char)convertionSpec.GetIntArg();
00457 }
00458 else if(c=='p')
00459 {
00460 ulonglong val = (ulonglong)(uintptr_t)convertionSpec.GetPointerArg();
00461 string = PushHex(val,string,sizeof(void*)*2,'x',false);
00462 }
00463 else if(c=='s')
00464 {
00465 string = (char*)convertionSpec.GetPointerArg();
00466 stringEnd = string;
00467 int precision = convertionSpec.Precision;
00468 while(*stringEnd++ && precision--) {}
00469 --stringEnd;
00470 }
00471 else if(c=='n')
00472 {
00473 void* ptr = convertionSpec.GetPointerArg();
00474 if(flags&LengthMod_ll) *(longlong*)ptr = outSize;
00475 else if(flags&LengthMod_l) *(long*)ptr = outSize;
00476 else if(flags&LengthMod_h) *(short*)ptr = outSize;
00477 else if(flags&LengthMod_hh) *(signed char*)ptr = outSize;
00478 else *(int*)ptr = outSize;
00479 }
00480 else if(c!='d' && c!='i' && c!='o' && c!='u' && c!='x' && c!='X')
00481 {
00482 string = UnkownFormat(stringEnd,convertionSpec);
00483 }
00484 else
00485 {
00486
00487 const int MaxPrecision = FormatTextBufferSize-2;
00488 int precision = convertionSpec.Precision;
00489 if(precision>MaxPrecision)
00490 precision = MaxPrecision;
00491 if(precision>=0)
00492 flags &= ~FlagZero;
00493
00494 if(c=='d' || c=='i')
00495 {
00496 longlong val = convertionSpec.GetIntArg(flags|SignedInt);
00497 char sign = 0;
00498 if(val<0)
00499 {
00500 sign = '-';
00501 val = -val;
00502 }
00503 else if(flags&FlagPlus)
00504 sign = '+';
00505 else if(flags&FlagSpace)
00506 sign = ' ';
00507 string = PushDecimal(val,string,precision);
00508 if(sign)
00509 {
00510 zeroPadPosition = 1;
00511 *--string = sign;
00512 }
00513 }
00514 else
00515 {
00516 ulonglong val = convertionSpec.GetIntArg(flags);
00517 if(c=='u')
00518 {
00519 string = PushDecimal(val,string,precision);
00520 }
00521 else if(c=='o')
00522 {
00523 string = PushOctal(val,string,precision,flags&FlagHash);
00524 }
00525 else
00526 {
00527 if(flags&FlagHash)
00528 zeroPadPosition = 2;
00529 string = PushHex(val,string,precision,c,flags&FlagHash);
00530 }
00531 }
00532 }
00533
00534
00535 char* padPoint;
00536 char pad = ' ';
00537 if(flags&FlagMinus)
00538 {
00539 padPoint = stringEnd;
00540 }
00541 else if(flags&FlagZero)
00542 {
00543 pad = '0';
00544 padPoint = string+zeroPadPosition;
00545 if(padPoint<string || padPoint>stringEnd)
00546 padPoint = stringEnd;
00547 }
00548 else
00549 {
00550 padPoint = string;
00551 }
00552
00553
00554 int width = stringEnd-string;
00555
00556
00557 size = padPoint-string;
00558 outSize += size;
00559 Out(string,size);
00560 string += size;
00561
00562
00563 int fieldWidth = convertionSpec.FieldWidth;
00564 if(width<fieldWidth)
00565 {
00566 size = fieldWidth-width;
00567 outSize += size;
00568 Out(pad,size);
00569 }
00570
00571
00572 size = stringEnd-string;
00573 outSize += size;
00574 Out(string,size);
00575 string += size;
00576 }
00577 }
00578
00579
00580 size_t StringFormatter::Format(const char* formatString, ...)
00581 {
00582 va_list args;
00583 va_start(args,formatString);
00584 size_t size = VFormat(formatString,args);
00585 va_end(args);
00586 return size;
00587 }
00588
00589
00590 ASSERT_COMPILE(16/sizeof(void*)*sizeof(void*)==16);
00591
00592 size_t StringFormatter::HexDumpLine(const void* data, size_t size, ptrdiff_t addressOffset)
00593 {
00594 const uint8_t* src = (const uint8_t*)data;
00595 char bytes[16];
00596
00597 Format("%0*x",sizeof(void*)*2,src+addressOffset);
00598
00599 for(unsigned i=0; i<16; i++)
00600 {
00601 const char* format;
00602 unsigned b;
00603 if(i<size)
00604 {
00605 b = *src++;
00606 format = "%*.2x";
00607 }
00608 else
00609 {
00610 b = ' ';
00611 format = "%*c";
00612 }
00613 int width = (i&(sizeof(uintptr_t)-1))==0 ? 4 : 3;
00614
00615 Format(format,width,b);
00616
00617 if(b<32 || b>0x7e)
00618 b = '.';
00619 bytes[i] = b;
00620 }
00621
00622 Format(" %.16s\n",bytes);
00623
00624 return size>16 ? size-16 : 0;
00625 }
00626
00627
00628
00629
00630
00631
00632
00633 StringBufferFormatter::StringBufferFormatter(char* buffer, size_t size)
00634 {
00635 BufferStart = buffer;
00636 BufferPtr = buffer;
00637 char* end = buffer+size;
00638 if(end<buffer)
00639 end = (char*)~(uintptr_t)0;
00640 BufferEnd = end;
00641 }
00642
00643
00644 void StringBufferFormatter::Out(const char* text, size_t textSize)
00645 {
00646 char* out = BufferPtr;
00647 char* end = out+textSize;
00648 if(end>BufferEnd || end<out)
00649 end = BufferEnd;
00650 while(out<end)
00651 *out++ = *text++;
00652 BufferPtr = out;
00653 }
00654
00655
00656 void StringBufferFormatter::Out(char character, size_t repeatCount)
00657 {
00658 char* out = BufferPtr;
00659 char* end = out+repeatCount;
00660 if(end>BufferEnd || end<out)
00661 end = BufferEnd;
00662 while(out<end)
00663 *out++ = character;
00664 BufferPtr = out;
00665 }
00666
00667
00668 char* StringBufferFormatter::End()
00669 {
00670 char* end = BufferPtr;
00671 if(end<BufferEnd)
00672 *end = 0;
00673 BufferPtr = BufferStart;
00674 return end;
00675 }
00676
00677
00678
00679
00680
00681
00682
00683 extern "C" int vsprintf(char* str, const char* format, va_list ap)
00684 {
00685 StringBufferFormatter formatter(str,~(size_t)0);
00686 int len = formatter.VFormat(format, ap);
00687 formatter.End();
00688 return len;
00689 }
00690
00691
00692 extern "C" int sprintf(char* str, const char* format, ...)
00693 {
00694 va_list args;
00695 va_start(args,format);
00696 int len = vsprintf(str,format,args);
00697 va_end(args);
00698 return len;
00699 }
00700
00701
00702 extern "C" int vsnprintf(char* str, size_t size, const char* format, va_list ap)
00703 {
00704 StringBufferFormatter formatter(str,size);
00705 size_t len = formatter.VFormat(format, ap);
00706 formatter.End();
00707 if(len>=size && size)
00708 str[size-1] = 0;
00709 return len;
00710 }
00711
00712
00713 extern "C" int snprintf(char* str, size_t size, const char* format, ...)
00714 {
00715 va_list args;
00716 va_start(args,format);
00717 size = vsnprintf(str,size,format,args);
00718 va_end(args);
00719 return size;
00720 }
00721
00722