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
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 #include "replace.h"
00107 #include "system/locale.h"
00108
00109 #ifdef TEST_SNPRINTF
00110
00111
00112
00113 # undef HAVE_SNPRINTF
00114 # undef HAVE_VSNPRINTF
00115 # undef HAVE_C99_VSNPRINTF
00116 # undef HAVE_ASPRINTF
00117 # undef HAVE_VASPRINTF
00118 # include <math.h>
00119 #endif
00120
00121 #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
00122
00123 #include <stdio.h>
00124
00125 void dummy_snprintf(void);
00126 void dummy_snprintf(void) {}
00127 #endif
00128
00129
00130 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
00131
00132 #ifdef HAVE_LONG_DOUBLE
00133 #define LDOUBLE long double
00134 #else
00135 #define LDOUBLE double
00136 #endif
00137
00138 #ifdef HAVE_LONG_LONG
00139 #define LLONG long long
00140 #else
00141 #define LLONG long
00142 #endif
00143
00144 #ifndef VA_COPY
00145 #ifdef HAVE_VA_COPY
00146 #define VA_COPY(dest, src) va_copy(dest, src)
00147 #else
00148 #ifdef HAVE___VA_COPY
00149 #define VA_COPY(dest, src) __va_copy(dest, src)
00150 #else
00151 #define VA_COPY(dest, src) (dest) = (src)
00152 #endif
00153 #endif
00154
00155
00156
00157
00158
00159
00160 #define DP_S_DEFAULT 0
00161 #define DP_S_FLAGS 1
00162 #define DP_S_MIN 2
00163 #define DP_S_DOT 3
00164 #define DP_S_MAX 4
00165 #define DP_S_MOD 5
00166 #define DP_S_CONV 6
00167 #define DP_S_DONE 7
00168
00169
00170 #define DP_F_MINUS (1 << 0)
00171 #define DP_F_PLUS (1 << 1)
00172 #define DP_F_SPACE (1 << 2)
00173 #define DP_F_NUM (1 << 3)
00174 #define DP_F_ZERO (1 << 4)
00175 #define DP_F_UP (1 << 5)
00176 #define DP_F_UNSIGNED (1 << 6)
00177
00178
00179 #define DP_C_CHAR 1
00180 #define DP_C_SHORT 2
00181 #define DP_C_LONG 3
00182 #define DP_C_LDOUBLE 4
00183 #define DP_C_LLONG 5
00184 #define DP_C_SIZET 6
00185
00186
00187 #define CNK_FMT_STR 0
00188 #define CNK_INT 1
00189 #define CNK_OCTAL 2
00190 #define CNK_UINT 3
00191 #define CNK_HEX 4
00192 #define CNK_FLOAT 5
00193 #define CNK_CHAR 6
00194 #define CNK_STRING 7
00195 #define CNK_PTR 8
00196 #define CNK_NUM 9
00197 #define CNK_PRCNT 10
00198
00199 #define char_to_int(p) ((p)- '0')
00200 #ifndef MAX
00201 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
00202 #endif
00203
00204 struct pr_chunk {
00205 int type;
00206 int num;
00207 int min;
00208 int max;
00209 int flags;
00210 int cflags;
00211 int start;
00212 int len;
00213 LLONG value;
00214 LDOUBLE fvalue;
00215 char *strvalue;
00216 void *pnum;
00217 struct pr_chunk *min_star;
00218 struct pr_chunk *max_star;
00219 struct pr_chunk *next;
00220 };
00221
00222 struct pr_chunk_x {
00223 struct pr_chunk **chunks;
00224 int num;
00225 };
00226
00227 static int dopr(char *buffer, size_t maxlen, const char *format,
00228 va_list args_in);
00229 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
00230 char *value, int flags, int min, int max);
00231 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
00232 LLONG value, int base, int min, int max, int flags);
00233 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
00234 LDOUBLE fvalue, int min, int max, int flags);
00235 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
00236 static struct pr_chunk *new_chunk(void);
00237 static int add_cnk_list_entry(struct pr_chunk_x **list,
00238 int max_num, struct pr_chunk *chunk);
00239
00240 static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
00241 {
00242 char ch;
00243 int state;
00244 int pflag;
00245 int pnum;
00246 int pfirst;
00247 size_t currlen;
00248 va_list args;
00249 const char *base;
00250 struct pr_chunk *chunks = NULL;
00251 struct pr_chunk *cnk = NULL;
00252 struct pr_chunk_x *clist = NULL;
00253 int max_pos;
00254 int ret = -1;
00255
00256 VA_COPY(args, args_in);
00257
00258 state = DP_S_DEFAULT;
00259 pfirst = 1;
00260 pflag = 0;
00261 pnum = 0;
00262
00263 max_pos = 0;
00264 base = format;
00265 ch = *format++;
00266
00267
00268 while (state != DP_S_DONE) {
00269 if (ch == '\0')
00270 state = DP_S_DONE;
00271
00272 switch(state) {
00273 case DP_S_DEFAULT:
00274
00275 if (cnk) {
00276 cnk->next = new_chunk();
00277 cnk = cnk->next;
00278 } else {
00279 cnk = new_chunk();
00280 }
00281 if (!cnk) goto done;
00282 if (!chunks) chunks = cnk;
00283
00284 if (ch == '%') {
00285 state = DP_S_FLAGS;
00286 ch = *format++;
00287 } else {
00288 cnk->type = CNK_FMT_STR;
00289 cnk->start = format - base -1;
00290 while ((ch != '\0') && (ch != '%')) ch = *format++;
00291 cnk->len = format - base - cnk->start -1;
00292 }
00293 break;
00294 case DP_S_FLAGS:
00295 switch (ch) {
00296 case '-':
00297 cnk->flags |= DP_F_MINUS;
00298 ch = *format++;
00299 break;
00300 case '+':
00301 cnk->flags |= DP_F_PLUS;
00302 ch = *format++;
00303 break;
00304 case ' ':
00305 cnk->flags |= DP_F_SPACE;
00306 ch = *format++;
00307 break;
00308 case '#':
00309 cnk->flags |= DP_F_NUM;
00310 ch = *format++;
00311 break;
00312 case '0':
00313 cnk->flags |= DP_F_ZERO;
00314 ch = *format++;
00315 break;
00316 case 'I':
00317
00318 ch = *format++;
00319 break;
00320 default:
00321 state = DP_S_MIN;
00322 break;
00323 }
00324 break;
00325 case DP_S_MIN:
00326 if (isdigit((unsigned char)ch)) {
00327 cnk->min = 10 * cnk->min + char_to_int (ch);
00328 ch = *format++;
00329 } else if (ch == '$') {
00330 if (!pfirst && !pflag) {
00331
00332 goto done;
00333 }
00334 if (pfirst) {
00335 pfirst = 0;
00336 pflag = 1;
00337 }
00338 if (cnk->min == 0)
00339 goto done;
00340 cnk->num = cnk->min;
00341 cnk->min = 0;
00342 ch = *format++;
00343 } else if (ch == '*') {
00344 if (pfirst) pfirst = 0;
00345 cnk->min_star = new_chunk();
00346 if (!cnk->min_star)
00347 goto done;
00348 cnk->min_star->type = CNK_INT;
00349 if (pflag) {
00350 int num;
00351 ch = *format++;
00352 if (!isdigit((unsigned char)ch)) {
00353
00354 goto done;
00355 }
00356 for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
00357 num = 10 * num + char_to_int(ch);
00358 }
00359 cnk->min_star->num = num;
00360 if (ch != '$')
00361 goto done;
00362 } else {
00363 cnk->min_star->num = ++pnum;
00364 }
00365 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
00366 if (max_pos == 0)
00367 goto done;
00368 ch = *format++;
00369 state = DP_S_DOT;
00370 } else {
00371 if (pfirst) pfirst = 0;
00372 state = DP_S_DOT;
00373 }
00374 break;
00375 case DP_S_DOT:
00376 if (ch == '.') {
00377 state = DP_S_MAX;
00378 ch = *format++;
00379 } else {
00380 state = DP_S_MOD;
00381 }
00382 break;
00383 case DP_S_MAX:
00384 if (isdigit((unsigned char)ch)) {
00385 if (cnk->max < 0)
00386 cnk->max = 0;
00387 cnk->max = 10 * cnk->max + char_to_int (ch);
00388 ch = *format++;
00389 } else if (ch == '$') {
00390 if (!pfirst && !pflag) {
00391
00392 goto done;
00393 }
00394 if (cnk->max <= 0)
00395 goto done;
00396 cnk->num = cnk->max;
00397 cnk->max = -1;
00398 ch = *format++;
00399 } else if (ch == '*') {
00400 cnk->max_star = new_chunk();
00401 if (!cnk->max_star)
00402 goto done;
00403 cnk->max_star->type = CNK_INT;
00404 if (pflag) {
00405 int num;
00406 ch = *format++;
00407 if (!isdigit((unsigned char)ch)) {
00408
00409 goto done;
00410 }
00411 for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
00412 num = 10 * num + char_to_int(ch);
00413 }
00414 cnk->max_star->num = num;
00415 if (ch != '$')
00416 goto done;
00417 } else {
00418 cnk->max_star->num = ++pnum;
00419 }
00420 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
00421 if (max_pos == 0)
00422 goto done;
00423
00424 ch = *format++;
00425 state = DP_S_MOD;
00426 } else {
00427 state = DP_S_MOD;
00428 }
00429 break;
00430 case DP_S_MOD:
00431 switch (ch) {
00432 case 'h':
00433 cnk->cflags = DP_C_SHORT;
00434 ch = *format++;
00435 if (ch == 'h') {
00436 cnk->cflags = DP_C_CHAR;
00437 ch = *format++;
00438 }
00439 break;
00440 case 'l':
00441 cnk->cflags = DP_C_LONG;
00442 ch = *format++;
00443 if (ch == 'l') {
00444 cnk->cflags = DP_C_LLONG;
00445 ch = *format++;
00446 }
00447 break;
00448 case 'L':
00449 cnk->cflags = DP_C_LDOUBLE;
00450 ch = *format++;
00451 break;
00452 case 'z':
00453 cnk->cflags = DP_C_SIZET;
00454 ch = *format++;
00455 break;
00456 default:
00457 break;
00458 }
00459 state = DP_S_CONV;
00460 break;
00461 case DP_S_CONV:
00462 if (cnk->num == 0) cnk->num = ++pnum;
00463 max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
00464 if (max_pos == 0)
00465 goto done;
00466
00467 switch (ch) {
00468 case 'd':
00469 case 'i':
00470 cnk->type = CNK_INT;
00471 break;
00472 case 'o':
00473 cnk->type = CNK_OCTAL;
00474 cnk->flags |= DP_F_UNSIGNED;
00475 break;
00476 case 'u':
00477 cnk->type = CNK_UINT;
00478 cnk->flags |= DP_F_UNSIGNED;
00479 break;
00480 case 'X':
00481 cnk->flags |= DP_F_UP;
00482 case 'x':
00483 cnk->type = CNK_HEX;
00484 cnk->flags |= DP_F_UNSIGNED;
00485 break;
00486 case 'A':
00487
00488 case 'E':
00489 case 'G':
00490 case 'F':
00491 cnk->flags |= DP_F_UP;
00492 case 'a':
00493
00494 case 'e':
00495 case 'f':
00496 case 'g':
00497 cnk->type = CNK_FLOAT;
00498 break;
00499 case 'c':
00500 cnk->type = CNK_CHAR;
00501 break;
00502 case 's':
00503 cnk->type = CNK_STRING;
00504 break;
00505 case 'p':
00506 cnk->type = CNK_PTR;
00507 break;
00508 case 'n':
00509 cnk->type = CNK_NUM;
00510 break;
00511 case '%':
00512 cnk->type = CNK_PRCNT;
00513 break;
00514 default:
00515
00516 goto done;
00517 }
00518 ch = *format++;
00519 state = DP_S_DEFAULT;
00520 break;
00521 case DP_S_DONE:
00522 break;
00523 default:
00524
00525 break;
00526 }
00527 }
00528
00529
00530 for (pnum = 0; pnum < max_pos; pnum++) {
00531 int i;
00532
00533 if (clist[pnum].num == 0) {
00534
00535
00536
00537
00538
00539 #ifdef DEBUG_SNPRINTF
00540 printf("parameter at position %d not used\n", pnum+1);
00541 #endif
00542
00543 va_arg (args, int);
00544 continue;
00545 }
00546 for (i = 1; i < clist[pnum].num; i++) {
00547 if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
00548
00549
00550
00551
00552 goto done;
00553 }
00554 }
00555 cnk = clist[pnum].chunks[0];
00556 switch (cnk->type) {
00557 case CNK_INT:
00558 if (cnk->cflags == DP_C_SHORT)
00559 cnk->value = va_arg (args, int);
00560 else if (cnk->cflags == DP_C_LONG)
00561 cnk->value = va_arg (args, long int);
00562 else if (cnk->cflags == DP_C_LLONG)
00563 cnk->value = va_arg (args, LLONG);
00564 else if (cnk->cflags == DP_C_SIZET)
00565 cnk->value = va_arg (args, ssize_t);
00566 else
00567 cnk->value = va_arg (args, int);
00568
00569 for (i = 1; i < clist[pnum].num; i++) {
00570 clist[pnum].chunks[i]->value = cnk->value;
00571 }
00572 break;
00573
00574 case CNK_OCTAL:
00575 case CNK_UINT:
00576 case CNK_HEX:
00577 if (cnk->cflags == DP_C_SHORT)
00578 cnk->value = va_arg (args, unsigned int);
00579 else if (cnk->cflags == DP_C_LONG)
00580 cnk->value = (unsigned long int)va_arg (args, unsigned long int);
00581 else if (cnk->cflags == DP_C_LLONG)
00582 cnk->value = (LLONG)va_arg (args, unsigned LLONG);
00583 else if (cnk->cflags == DP_C_SIZET)
00584 cnk->value = (size_t)va_arg (args, size_t);
00585 else
00586 cnk->value = (unsigned int)va_arg (args, unsigned int);
00587
00588 for (i = 1; i < clist[pnum].num; i++) {
00589 clist[pnum].chunks[i]->value = cnk->value;
00590 }
00591 break;
00592
00593 case CNK_FLOAT:
00594 if (cnk->cflags == DP_C_LDOUBLE)
00595 cnk->fvalue = va_arg (args, LDOUBLE);
00596 else
00597 cnk->fvalue = va_arg (args, double);
00598
00599 for (i = 1; i < clist[pnum].num; i++) {
00600 clist[pnum].chunks[i]->fvalue = cnk->fvalue;
00601 }
00602 break;
00603
00604 case CNK_CHAR:
00605 cnk->value = va_arg (args, int);
00606
00607 for (i = 1; i < clist[pnum].num; i++) {
00608 clist[pnum].chunks[i]->value = cnk->value;
00609 }
00610 break;
00611
00612 case CNK_STRING:
00613 cnk->strvalue = va_arg (args, char *);
00614 if (!cnk->strvalue) cnk->strvalue = "(NULL)";
00615
00616 for (i = 1; i < clist[pnum].num; i++) {
00617 clist[pnum].chunks[i]->strvalue = cnk->strvalue;
00618 }
00619 break;
00620
00621 case CNK_PTR:
00622 cnk->strvalue = va_arg (args, void *);
00623 for (i = 1; i < clist[pnum].num; i++) {
00624 clist[pnum].chunks[i]->strvalue = cnk->strvalue;
00625 }
00626 break;
00627
00628 case CNK_NUM:
00629 if (cnk->cflags == DP_C_CHAR)
00630 cnk->pnum = va_arg (args, char *);
00631 else if (cnk->cflags == DP_C_SHORT)
00632 cnk->pnum = va_arg (args, short int *);
00633 else if (cnk->cflags == DP_C_LONG)
00634 cnk->pnum = va_arg (args, long int *);
00635 else if (cnk->cflags == DP_C_LLONG)
00636 cnk->pnum = va_arg (args, LLONG *);
00637 else if (cnk->cflags == DP_C_SIZET)
00638 cnk->pnum = va_arg (args, ssize_t *);
00639 else
00640 cnk->pnum = va_arg (args, int *);
00641
00642 for (i = 1; i < clist[pnum].num; i++) {
00643 clist[pnum].chunks[i]->pnum = cnk->pnum;
00644 }
00645 break;
00646
00647 case CNK_PRCNT:
00648 break;
00649
00650 default:
00651
00652 goto done;
00653 }
00654 }
00655
00656 currlen = 0;
00657 cnk = chunks;
00658 while (cnk) {
00659 int len, min, max;
00660
00661 if (cnk->min_star) min = cnk->min_star->value;
00662 else min = cnk->min;
00663 if (cnk->max_star) max = cnk->max_star->value;
00664 else max = cnk->max;
00665
00666 switch (cnk->type) {
00667
00668 case CNK_FMT_STR:
00669 if (maxlen != 0 && maxlen > currlen) {
00670 if (maxlen > (currlen + cnk->len)) len = cnk->len;
00671 else len = maxlen - currlen;
00672
00673 memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
00674 }
00675 currlen += cnk->len;
00676
00677 break;
00678
00679 case CNK_INT:
00680 case CNK_UINT:
00681 fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
00682 break;
00683
00684 case CNK_OCTAL:
00685 fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
00686 break;
00687
00688 case CNK_HEX:
00689 fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
00690 break;
00691
00692 case CNK_FLOAT:
00693 fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
00694 break;
00695
00696 case CNK_CHAR:
00697 dopr_outch (buffer, &currlen, maxlen, cnk->value);
00698 break;
00699
00700 case CNK_STRING:
00701 if (max == -1) {
00702 max = strlen(cnk->strvalue);
00703 }
00704 fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
00705 break;
00706
00707 case CNK_PTR:
00708 fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
00709 break;
00710
00711 case CNK_NUM:
00712 if (cnk->cflags == DP_C_CHAR)
00713 *((char *)(cnk->pnum)) = (char)currlen;
00714 else if (cnk->cflags == DP_C_SHORT)
00715 *((short int *)(cnk->pnum)) = (short int)currlen;
00716 else if (cnk->cflags == DP_C_LONG)
00717 *((long int *)(cnk->pnum)) = (long int)currlen;
00718 else if (cnk->cflags == DP_C_LLONG)
00719 *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
00720 else if (cnk->cflags == DP_C_SIZET)
00721 *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
00722 else
00723 *((int *)(cnk->pnum)) = (int)currlen;
00724 break;
00725
00726 case CNK_PRCNT:
00727 dopr_outch (buffer, &currlen, maxlen, '%');
00728 break;
00729
00730 default:
00731
00732 goto done;
00733 }
00734 cnk = cnk->next;
00735 }
00736 if (maxlen != 0) {
00737 if (currlen < maxlen - 1)
00738 buffer[currlen] = '\0';
00739 else if (maxlen > 0)
00740 buffer[maxlen - 1] = '\0';
00741 }
00742 ret = currlen;
00743
00744 done:
00745 va_end(args);
00746
00747 while (chunks) {
00748 cnk = chunks->next;
00749 free(chunks);
00750 chunks = cnk;
00751 }
00752 if (clist) {
00753 for (pnum = 0; pnum < max_pos; pnum++) {
00754 if (clist[pnum].chunks) free(clist[pnum].chunks);
00755 }
00756 free(clist);
00757 }
00758 return ret;
00759 }
00760
00761 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
00762 char *value, int flags, int min, int max)
00763 {
00764 int padlen, strln;
00765 int cnt = 0;
00766
00767 #ifdef DEBUG_SNPRINTF
00768 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
00769 #endif
00770 if (value == 0) {
00771 value = "<NULL>";
00772 }
00773
00774 for (strln = 0; strln < max && value[strln]; ++strln);
00775 padlen = min - strln;
00776 if (padlen < 0)
00777 padlen = 0;
00778 if (flags & DP_F_MINUS)
00779 padlen = -padlen;
00780
00781 while (padlen > 0) {
00782 dopr_outch (buffer, currlen, maxlen, ' ');
00783 --padlen;
00784 }
00785 while (*value && (cnt < max)) {
00786 dopr_outch (buffer, currlen, maxlen, *value++);
00787 ++cnt;
00788 }
00789 while (padlen < 0) {
00790 dopr_outch (buffer, currlen, maxlen, ' ');
00791 ++padlen;
00792 }
00793 }
00794
00795
00796
00797 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
00798 LLONG value, int base, int min, int max, int flags)
00799 {
00800 int signvalue = 0;
00801 unsigned LLONG uvalue;
00802 char convert[20];
00803 int place = 0;
00804 int spadlen = 0;
00805 int zpadlen = 0;
00806 int caps = 0;
00807
00808 if (max < 0)
00809 max = 0;
00810
00811 uvalue = value;
00812
00813 if(!(flags & DP_F_UNSIGNED)) {
00814 if( value < 0 ) {
00815 signvalue = '-';
00816 uvalue = -value;
00817 } else {
00818 if (flags & DP_F_PLUS)
00819 signvalue = '+';
00820 else if (flags & DP_F_SPACE)
00821 signvalue = ' ';
00822 }
00823 }
00824
00825 if (flags & DP_F_UP) caps = 1;
00826
00827 do {
00828 convert[place++] =
00829 (caps? "0123456789ABCDEF":"0123456789abcdef")
00830 [uvalue % (unsigned)base ];
00831 uvalue = (uvalue / (unsigned)base );
00832 } while(uvalue && (place < 20));
00833 if (place == 20) place--;
00834 convert[place] = 0;
00835
00836 zpadlen = max - place;
00837 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
00838 if (zpadlen < 0) zpadlen = 0;
00839 if (spadlen < 0) spadlen = 0;
00840 if (flags & DP_F_ZERO) {
00841 zpadlen = MAX(zpadlen, spadlen);
00842 spadlen = 0;
00843 }
00844 if (flags & DP_F_MINUS)
00845 spadlen = -spadlen;
00846
00847 #ifdef DEBUG_SNPRINTF
00848 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
00849 zpadlen, spadlen, min, max, place);
00850 #endif
00851
00852
00853 while (spadlen > 0) {
00854 dopr_outch (buffer, currlen, maxlen, ' ');
00855 --spadlen;
00856 }
00857
00858
00859 if (signvalue)
00860 dopr_outch (buffer, currlen, maxlen, signvalue);
00861
00862
00863 if (zpadlen > 0) {
00864 while (zpadlen > 0) {
00865 dopr_outch (buffer, currlen, maxlen, '0');
00866 --zpadlen;
00867 }
00868 }
00869
00870
00871 while (place > 0)
00872 dopr_outch (buffer, currlen, maxlen, convert[--place]);
00873
00874
00875 while (spadlen < 0) {
00876 dopr_outch (buffer, currlen, maxlen, ' ');
00877 ++spadlen;
00878 }
00879 }
00880
00881 static LDOUBLE abs_val(LDOUBLE value)
00882 {
00883 LDOUBLE result = value;
00884
00885 if (value < 0)
00886 result = -value;
00887
00888 return result;
00889 }
00890
00891 static LDOUBLE POW10(int exp)
00892 {
00893 LDOUBLE result = 1;
00894
00895 while (exp) {
00896 result *= 10;
00897 exp--;
00898 }
00899
00900 return result;
00901 }
00902
00903 static LLONG ROUND(LDOUBLE value)
00904 {
00905 LLONG intpart;
00906
00907 intpart = (LLONG)value;
00908 value = value - intpart;
00909 if (value >= 0.5) intpart++;
00910
00911 return intpart;
00912 }
00913
00914
00915
00916 static double my_modf(double x0, double *iptr)
00917 {
00918 int i;
00919 LLONG l=0;
00920 double x = x0;
00921 double f = 1.0;
00922
00923 for (i=0;i<100;i++) {
00924 l = (long)x;
00925 if (l <= (x+1) && l >= (x-1)) break;
00926 x *= 0.1;
00927 f *= 10.0;
00928 }
00929
00930 if (i == 100) {
00931
00932 (*iptr) = 0;
00933 return 0;
00934 }
00935
00936 if (i != 0) {
00937 double i2;
00938 double ret;
00939
00940 ret = my_modf(x0-l*f, &i2);
00941 (*iptr) = l*f + i2;
00942 return ret;
00943 }
00944
00945 (*iptr) = l;
00946 return x - (*iptr);
00947 }
00948
00949
00950 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
00951 LDOUBLE fvalue, int min, int max, int flags)
00952 {
00953 int signvalue = 0;
00954 double ufvalue;
00955 char iconvert[311];
00956 char fconvert[311];
00957 int iplace = 0;
00958 int fplace = 0;
00959 int padlen = 0;
00960 int zpadlen = 0;
00961 int caps = 0;
00962 int idx;
00963 double intpart;
00964 double fracpart;
00965 double temp;
00966
00967
00968
00969
00970
00971 if (max < 0)
00972 max = 6;
00973
00974 ufvalue = abs_val (fvalue);
00975
00976 if (fvalue < 0) {
00977 signvalue = '-';
00978 } else {
00979 if (flags & DP_F_PLUS) {
00980 signvalue = '+';
00981 } else {
00982 if (flags & DP_F_SPACE)
00983 signvalue = ' ';
00984 }
00985 }
00986
00987 #if 0
00988 if (flags & DP_F_UP) caps = 1;
00989 #endif
00990
00991 #if 0
00992 if (max == 0) ufvalue += 0.5;
00993 #endif
00994
00995
00996
00997
00998
00999 if (max > 9)
01000 max = 9;
01001
01002
01003
01004
01005
01006 temp = ufvalue;
01007 my_modf(temp, &intpart);
01008
01009 fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
01010
01011 if (fracpart >= POW10(max)) {
01012 intpart++;
01013 fracpart -= POW10(max);
01014 }
01015
01016
01017
01018 do {
01019 temp = intpart*0.1;
01020 my_modf(temp, &intpart);
01021 idx = (int) ((temp -intpart +0.05)* 10.0);
01022
01023
01024 iconvert[iplace++] =
01025 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
01026 } while (intpart && (iplace < 311));
01027 if (iplace == 311) iplace--;
01028 iconvert[iplace] = 0;
01029
01030
01031 if (fracpart)
01032 {
01033 do {
01034 temp = fracpart*0.1;
01035 my_modf(temp, &fracpart);
01036 idx = (int) ((temp -fracpart +0.05)* 10.0);
01037
01038
01039 fconvert[fplace++] =
01040 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
01041 } while(fracpart && (fplace < 311));
01042 if (fplace == 311) fplace--;
01043 }
01044 fconvert[fplace] = 0;
01045
01046
01047 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
01048 zpadlen = max - fplace;
01049 if (zpadlen < 0) zpadlen = 0;
01050 if (padlen < 0)
01051 padlen = 0;
01052 if (flags & DP_F_MINUS)
01053 padlen = -padlen;
01054
01055 if ((flags & DP_F_ZERO) && (padlen > 0)) {
01056 if (signvalue) {
01057 dopr_outch (buffer, currlen, maxlen, signvalue);
01058 --padlen;
01059 signvalue = 0;
01060 }
01061 while (padlen > 0) {
01062 dopr_outch (buffer, currlen, maxlen, '0');
01063 --padlen;
01064 }
01065 }
01066 while (padlen > 0) {
01067 dopr_outch (buffer, currlen, maxlen, ' ');
01068 --padlen;
01069 }
01070 if (signvalue)
01071 dopr_outch (buffer, currlen, maxlen, signvalue);
01072
01073 while (iplace > 0)
01074 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
01075
01076 #ifdef DEBUG_SNPRINTF
01077 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
01078 #endif
01079
01080
01081
01082
01083
01084 if (max > 0) {
01085 dopr_outch (buffer, currlen, maxlen, '.');
01086
01087 while (zpadlen > 0) {
01088 dopr_outch (buffer, currlen, maxlen, '0');
01089 --zpadlen;
01090 }
01091
01092 while (fplace > 0)
01093 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
01094 }
01095
01096 while (padlen < 0) {
01097 dopr_outch (buffer, currlen, maxlen, ' ');
01098 ++padlen;
01099 }
01100 }
01101
01102 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
01103 {
01104 if (*currlen < maxlen) {
01105 buffer[(*currlen)] = c;
01106 }
01107 (*currlen)++;
01108 }
01109
01110 static struct pr_chunk *new_chunk(void) {
01111 struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
01112
01113 if (!new_c)
01114 return NULL;
01115
01116 new_c->type = 0;
01117 new_c->num = 0;
01118 new_c->min = 0;
01119 new_c->min_star = NULL;
01120 new_c->max = -1;
01121 new_c->max_star = NULL;
01122 new_c->flags = 0;
01123 new_c->cflags = 0;
01124 new_c->start = 0;
01125 new_c->len = 0;
01126 new_c->value = 0;
01127 new_c->fvalue = 0;
01128 new_c->strvalue = NULL;
01129 new_c->pnum = NULL;
01130 new_c->next = NULL;
01131
01132 return new_c;
01133 }
01134
01135 static int add_cnk_list_entry(struct pr_chunk_x **list,
01136 int max_num, struct pr_chunk *chunk) {
01137 struct pr_chunk_x *l;
01138 struct pr_chunk **c;
01139 int max;
01140 int cnum;
01141 int i, pos;
01142
01143 if (chunk->num > max_num) {
01144 max = chunk->num;
01145
01146 if (*list == NULL) {
01147 l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
01148 pos = 0;
01149 } else {
01150 l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
01151 pos = max_num;
01152 }
01153 if (l == NULL) {
01154 for (i = 0; i < max; i++) {
01155 if ((*list)[i].chunks) free((*list)[i].chunks);
01156 }
01157 return 0;
01158 }
01159 for (i = pos; i < max; i++) {
01160 l[i].chunks = NULL;
01161 l[i].num = 0;
01162 }
01163 } else {
01164 l = *list;
01165 max = max_num;
01166 }
01167
01168 i = chunk->num - 1;
01169 cnum = l[i].num + 1;
01170 if (l[i].chunks == NULL) {
01171 c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum);
01172 } else {
01173 c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
01174 }
01175 if (c == NULL) {
01176 for (i = 0; i < max; i++) {
01177 if (l[i].chunks) free(l[i].chunks);
01178 }
01179 return 0;
01180 }
01181 c[l[i].num] = chunk;
01182 l[i].chunks = c;
01183 l[i].num = cnum;
01184
01185 *list = l;
01186 return max;
01187 }
01188
01189 int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
01190 {
01191 return dopr(str, count, fmt, args);
01192 }
01193 #endif
01194
01195
01196
01197
01198
01199
01200
01201 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
01202 int snprintf(char *str,size_t count,const char *fmt,...)
01203 {
01204 size_t ret;
01205 va_list ap;
01206
01207 va_start(ap, fmt);
01208 ret = vsnprintf(str, count, fmt, ap);
01209 va_end(ap);
01210 return ret;
01211 }
01212 #endif
01213
01214 #ifndef HAVE_C99_VSNPRINTF
01215 int printf(const char *fmt, ...)
01216 {
01217 va_list ap;
01218 int ret;
01219 char *s;
01220
01221 s = NULL;
01222 va_start(ap, fmt);
01223 ret = vasprintf(&s, fmt, ap);
01224 va_end(ap);
01225
01226 if (s) {
01227 fwrite(s, 1, strlen(s), stdout);
01228 }
01229 free(s);
01230
01231 return ret;
01232 }
01233 #endif
01234
01235 #ifndef HAVE_C99_VSNPRINTF
01236 int fprintf(FILE *stream, const char *fmt, ...)
01237 {
01238 va_list ap;
01239 int ret;
01240 char *s;
01241
01242 s = NULL;
01243 va_start(ap, fmt);
01244 ret = vasprintf(&s, fmt, ap);
01245 va_end(ap);
01246
01247 if (s) {
01248 fwrite(s, 1, strlen(s), stream);
01249 }
01250 free(s);
01251
01252 return ret;
01253 }
01254 #endif
01255
01256 #endif
01257
01258 #ifndef HAVE_VASPRINTF
01259 int vasprintf(char **ptr, const char *format, va_list ap)
01260 {
01261 int ret;
01262 va_list ap2;
01263
01264 VA_COPY(ap2, ap);
01265 ret = vsnprintf(NULL, 0, format, ap2);
01266 va_end(ap2);
01267 if (ret <= 0) return ret;
01268
01269 (*ptr) = (char *)malloc(ret+1);
01270 if (!*ptr) return -1;
01271
01272 VA_COPY(ap2, ap);
01273 ret = vsnprintf(*ptr, ret+1, format, ap2);
01274 va_end(ap2);
01275
01276 return ret;
01277 }
01278 #endif
01279
01280
01281 #ifndef HAVE_ASPRINTF
01282 int asprintf(char **ptr, const char *format, ...)
01283 {
01284 va_list ap;
01285 int ret;
01286
01287 *ptr = NULL;
01288 va_start(ap, format);
01289 ret = vasprintf(ptr, format, ap);
01290 va_end(ap);
01291
01292 return ret;
01293 }
01294 #endif
01295
01296 #ifdef TEST_SNPRINTF
01297
01298 int sprintf(char *str,const char *fmt,...);
01299 int printf(const char *fmt,...);
01300
01301 int main (void)
01302 {
01303 char buf1[1024];
01304 char buf2[1024];
01305 char *buf3;
01306 char *fp_fmt[] = {
01307 "%1.1f",
01308 "%-1.5f",
01309 "%1.5f",
01310 "%123.9f",
01311 "%10.5f",
01312 "% 10.5f",
01313 "%+22.9f",
01314 "%+4.9f",
01315 "%01.3f",
01316 "%4f",
01317 "%3.1f",
01318 "%3.2f",
01319 "%.0f",
01320 "%f",
01321 "%-8.8f",
01322 "%-9.9f",
01323 NULL
01324 };
01325 double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
01326 0.9996, 1.996, 4.136, 5.030201, 0.00205,
01327 0};
01328 char *int_fmt[] = {
01329 "%-1.5d",
01330 "%1.5d",
01331 "%123.9d",
01332 "%5.5d",
01333 "%10.5d",
01334 "% 10.5d",
01335 "%+22.33d",
01336 "%01.3d",
01337 "%4d",
01338 "%d",
01339 NULL
01340 };
01341 long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
01342 char *str_fmt[] = {
01343 "%10.5s",
01344 "%-10.5s",
01345 "%5.10s",
01346 "%-5.10s",
01347 "%10.1s",
01348 "%0.10s",
01349 "%10.0s",
01350 "%1.10s",
01351 "%s",
01352 "%.1s",
01353 "%.10s",
01354 "%10s",
01355 NULL
01356 };
01357 char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
01358 #ifdef HAVE_LONG_LONG
01359 char *ll_fmt[] = {
01360 "%llu",
01361 NULL
01362 };
01363 LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
01364 #endif
01365 int x, y;
01366 int fail = 0;
01367 int num = 0;
01368 int l1, l2;
01369 char *ss_fmt[] = {
01370 "%zd",
01371 "%zu",
01372 NULL
01373 };
01374 size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
01375
01376 printf ("Testing snprintf format codes against system sprintf...\n");
01377
01378 for (x = 0; fp_fmt[x] ; x++) {
01379 for (y = 0; fp_nums[y] != 0 ; y++) {
01380 buf1[0] = buf2[0] = '\0';
01381 l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
01382 l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
01383 buf1[1023] = buf2[1023] = '\0';
01384 if (strcmp (buf1, buf2) || (l1 != l2)) {
01385 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01386 fp_fmt[x], l1, buf1, l2, buf2);
01387 fail++;
01388 }
01389 num++;
01390 }
01391 }
01392
01393 for (x = 0; int_fmt[x] ; x++) {
01394 for (y = 0; int_nums[y] != 0 ; y++) {
01395 buf1[0] = buf2[0] = '\0';
01396 l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
01397 l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
01398 buf1[1023] = buf2[1023] = '\0';
01399 if (strcmp (buf1, buf2) || (l1 != l2)) {
01400 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01401 int_fmt[x], l1, buf1, l2, buf2);
01402 fail++;
01403 }
01404 num++;
01405 }
01406 }
01407
01408 for (x = 0; str_fmt[x] ; x++) {
01409 for (y = 0; str_vals[y] != 0 ; y++) {
01410 buf1[0] = buf2[0] = '\0';
01411 l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
01412 l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
01413 buf1[1023] = buf2[1023] = '\0';
01414 if (strcmp (buf1, buf2) || (l1 != l2)) {
01415 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01416 str_fmt[x], l1, buf1, l2, buf2);
01417 fail++;
01418 }
01419 num++;
01420 }
01421 }
01422
01423 #ifdef HAVE_LONG_LONG
01424 for (x = 0; ll_fmt[x] ; x++) {
01425 for (y = 0; ll_nums[y] != 0 ; y++) {
01426 buf1[0] = buf2[0] = '\0';
01427 l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
01428 l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
01429 buf1[1023] = buf2[1023] = '\0';
01430 if (strcmp (buf1, buf2) || (l1 != l2)) {
01431 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01432 ll_fmt[x], l1, buf1, l2, buf2);
01433 fail++;
01434 }
01435 num++;
01436 }
01437 }
01438 #endif
01439
01440 #define BUFSZ 2048
01441
01442 buf1[0] = buf2[0] = '\0';
01443 if ((buf3 = malloc(BUFSZ)) == NULL) {
01444 fail++;
01445 } else {
01446 num++;
01447 memset(buf3, 'a', BUFSZ);
01448 snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
01449 buf1[1023] = '\0';
01450 if (strcmp(buf1, "a") != 0) {
01451 printf("length limit buf1 '%s' expected 'a'\n", buf1);
01452 fail++;
01453 }
01454 }
01455
01456 buf1[0] = buf2[0] = '\0';
01457 l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
01458 l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
01459 buf1[1023] = buf2[1023] = '\0';
01460 if (strcmp(buf1, buf2) || (l1 != l2)) {
01461 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01462 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
01463 fail++;
01464 }
01465
01466 buf1[0] = buf2[0] = '\0';
01467 l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
01468 l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
01469 buf1[1023] = buf2[1023] = '\0';
01470 if (strcmp(buf1, buf2)) {
01471 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01472 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
01473 fail++;
01474 }
01475
01476 for (x = 0; ss_fmt[x] ; x++) {
01477 for (y = 0; ss_nums[y] != 0 ; y++) {
01478 buf1[0] = buf2[0] = '\0';
01479 l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
01480 l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
01481 buf1[1023] = buf2[1023] = '\0';
01482 if (strcmp (buf1, buf2) || (l1 != l2)) {
01483 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01484 ss_fmt[x], l1, buf1, l2, buf2);
01485 fail++;
01486 }
01487 num++;
01488 }
01489 }
01490 #if 0
01491 buf1[0] = buf2[0] = '\0';
01492 l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
01493 l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
01494 buf1[1023] = buf2[1023] = '\0';
01495 if (strcmp(buf1, buf2)) {
01496 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01497 "%lld", l1, buf1, l2, buf2);
01498 fail++;
01499 }
01500
01501 buf1[0] = buf2[0] = '\0';
01502 l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
01503 l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
01504 buf1[1023] = buf2[1023] = '\0';
01505 if (strcmp(buf1, buf2)) {
01506 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01507 "%Lf", l1, buf1, l2, buf2);
01508 fail++;
01509 }
01510 #endif
01511 printf ("%d tests failed out of %d.\n", fail, num);
01512
01513 printf("seeing how many digits we support\n");
01514 {
01515 double v0 = 0.12345678901234567890123456789012345678901;
01516 for (x=0; x<100; x++) {
01517 double p = pow(10, x);
01518 double r = v0*p;
01519 snprintf(buf1, sizeof(buf1), "%1.1f", r);
01520 sprintf(buf2, "%1.1f", r);
01521 if (strcmp(buf1, buf2)) {
01522 printf("we seem to support %d digits\n", x-1);
01523 break;
01524 }
01525 }
01526 }
01527
01528 return 0;
01529 }
01530 #endif