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 #include <stdarg.h>
00041 #include <stdint.h>
00042 #include <assert.h>
00043 #include <string.h>
00044
00045 #include <string>
00046 #include <iostream>
00047 #include <sstream>
00048
00049 #include <libsherpa/format.hxx>
00050
00051 namespace sherpa {
00052 std::string vformat(const char *fmt, va_list ap)
00053 {
00054 std::ostringstream oss;
00055
00056 #define PUT_DIGIT(d) \
00057 do { \
00058 *bufp = '0'+(d); \
00059 if (d >= 10) *bufp = (cnv + ((d)-10)); \
00060 bufp++; \
00061 } while(false)
00062
00063 while (*fmt) {
00064 if (*fmt != '%') {
00065 oss << *fmt++;
00066 continue;
00067 }
00068
00069
00070 fmt++;
00071
00072 {
00073 char buf[40];
00074 char *bufp = buf;
00075 char *sptr = 0;
00076 size_t slen = 0;
00077
00078 bool needSign = false;
00079 bool isNegative = false;
00080 bool ladjust = false;
00081 char posSign = ' ';
00082 unsigned width = 0;
00083 unsigned prec = 0;
00084 unsigned base = 10;
00085 char len = ' ';
00086 char padc = ' ';
00087 char cnv = ' ';
00088
00089
00090 for(;;) {
00091 switch (*fmt) {
00092 case ' ':
00093 {
00094 needSign = true;
00095 fmt++;
00096 continue;
00097 }
00098
00099 case '+':
00100 {
00101 needSign = true;
00102 posSign = '+';
00103 fmt++;
00104 continue;
00105 }
00106
00107 case '-':
00108 {
00109 ladjust = true;
00110 fmt++;
00111 continue;
00112 }
00113
00114 case '0':
00115 {
00116 padc = '0';
00117 fmt++;
00118 continue;
00119 }
00120
00121
00122 case '#':
00123 case '\'':
00124 case 'I':
00125 fmt++;
00126 continue;
00127
00128 default:
00129 break;
00130 }
00131
00132 break;
00133 }
00134
00135
00136 while (isdigit(*fmt)) {
00137 width *= 10;
00138 width += (*fmt - '0');
00139 fmt++;
00140 }
00141
00142
00143 if (*fmt == '.') {
00144 fmt++;
00145 while (isdigit(*fmt)) {
00146 prec *= 10;
00147 prec += (*fmt - '0');
00148 fmt++;
00149 }
00150 }
00151
00152
00153 switch (len = *fmt) {
00154 case 'h':
00155 {
00156 fmt++;
00157
00158 if (*fmt == 'h') {
00159 fmt++;
00160 len = 'c';
00161 }
00162 break;
00163 }
00164 case 'l':
00165 {
00166 fmt++;
00167 if (*fmt == 'l') {
00168 fmt++;
00169 len = 'q';
00170 }
00171 break;
00172 }
00173 #if 0
00174 case 'L':
00175 {
00176 fmt++;
00177 len = sizeof(long double);
00178 break;
00179 }
00180 #endif
00181
00182 case 'j':
00183 {
00184 fmt++;
00185 len = sizeof(intmax_t);
00186 break;
00187 }
00188 case 'z':
00189 {
00190 fmt++;
00191 len = sizeof(size_t);
00192 break;
00193 }
00194 case 't':
00195 {
00196 fmt++;
00197 len = sizeof(ptrdiff_t);
00198 break;
00199 }
00200 }
00201
00202
00203 switch (cnv = *fmt++) {
00204
00205 case 'o':
00206 {
00207 base = 8;
00208
00209 }
00210 case 'd':
00211 case 'i':
00212 {
00213 long long ll;
00214
00215 switch (len) {
00216 case 'q':
00217 ll = va_arg(ap, long long);
00218 break;
00219 case 'j':
00220 ll = va_arg(ap, intmax_t);
00221 break;
00222 case 'z':
00223 ll = va_arg(ap, size_t);
00224 break;
00225 case 't':
00226 ll = va_arg(ap, ptrdiff_t);
00227 break;
00228 default:
00229 ll = va_arg(ap, long);
00230 break;
00231 }
00232
00233 if (ll < 0ll) {
00234 isNegative = true;
00235 needSign = true;
00236 ll = -ll;
00237 }
00238
00239 if (ll == 0ll)
00240 PUT_DIGIT(0);
00241
00242 while (ll) {
00243 int digit = ll % base;
00244 ll = ll / base;
00245 PUT_DIGIT(digit);
00246 }
00247 break;
00248 }
00249 case 'p':
00250 {
00251 cnv = 'x';
00252 if (len == ' ')
00253 len = 'p';
00254
00255
00256 }
00257 case 'x':
00258 case 'X':
00259 {
00260 base = 16;
00261 cnv = cnv - ('x' - 'a');
00262
00263 }
00264 case 'u':
00265 {
00266 unsigned long long ull;
00267
00268 switch (len) {
00269 case 'q':
00270 ull = va_arg(ap, unsigned long long);
00271 break;
00272 case 'j':
00273 ull = va_arg(ap, intmax_t);
00274 break;
00275 case 'z':
00276 ull = va_arg(ap, size_t);
00277 break;
00278 case 't':
00279 ull = va_arg(ap, ptrdiff_t);
00280 break;
00281 case 'p':
00282 ull = (uintptr_t) va_arg(ap, void *);
00283 break;
00284 default:
00285 ull = va_arg(ap, unsigned long);
00286 break;
00287 }
00288
00289 if (ull == 0llu)
00290 PUT_DIGIT(0);
00291
00292 while (ull) {
00293 unsigned int digit = ull % base;
00294 ull = ull / base;
00295 PUT_DIGIT(digit);
00296 }
00297 break;
00298 }
00299 case 'c':
00300
00301 {
00302 char c = va_arg(ap, int);
00303 *bufp++ = c;
00304 break;
00305 }
00306 case 's':
00307
00308 {
00309 sptr = va_arg(ap, char *);
00310 slen = strlen(sptr);
00311 break;
00312 }
00313
00314 case '%':
00315 {
00316
00317 oss << '%';
00318 continue;
00319 }
00320 #if 0
00321
00322 case 'e':
00323 case 'E':
00324 case 'f':
00325 case 'F':
00326 case 'g':
00327 case 'G':
00328 case 'a':
00329 case 'A':
00330 {
00331 break;
00332 }
00333 #endif
00334 }
00335
00336 if (bufp != buf)
00337 slen = bufp - buf;
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 if (needSign && width)
00354 width--;
00355
00356 if (needSign) {
00357 oss << (isNegative ? '-' : posSign);
00358 }
00359
00360
00361
00362 if (ladjust == false) {
00363 while (slen < width) {
00364 oss << padc;
00365 slen++;
00366 }
00367 }
00368
00369 if (bufp != buf) {
00370 do {
00371 --bufp;
00372 oss << *bufp;
00373 } while (bufp != buf);
00374 }
00375 if (sptr)
00376 while(*sptr)
00377 oss << *sptr++;
00378
00379
00380 if (ladjust) {
00381 while (slen < width) {
00382 oss << padc;
00383 slen++;
00384 }
00385 }
00386 }
00387 }
00388
00389 return oss.str();
00390 }
00391
00392 std::string format(const char *fmt, ...)
00393 {
00394 va_list ap;
00395
00396 va_start(ap, fmt);
00397
00398 return vformat(fmt, ap);
00399
00400
00401 }
00402
00403 }