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