Index: builtin.c =================================================================== RCS file: /cvsroot/xmlgawk/xmlgawk/builtin.c,v retrieving revision 1.6 diff -b -u -p -r1.6 builtin.c --- builtin.c 14 Nov 2005 15:27:24 -0000 1.6 +++ builtin.c 23 Dec 2005 23:56:41 -0000 @@ -575,8 +575,13 @@ format_tree( uintmax_t uval; int sgn; int base = 0; - char cpbuf[30]; /* if we have numbers bigger than 30 */ - char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */ + struct { + char *buf; + size_t bufsize; + char stackbuf[30]; + } cpbufs[2]; +#define cpbuf cpbufs[0].buf + char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)]; char *cp; const char *fill; AWKNUM tmpval; @@ -585,6 +590,7 @@ format_tree( int zero_flag = FALSE; int quote_flag = FALSE; int ii, jj; + char *chp; static const char sp[] = " "; static const char zero_string[] = "0"; static const char lchbuf[] = "0123456789abcdef"; @@ -596,6 +602,29 @@ format_tree( osiz = INITIAL_OUT_SIZE; ofre = osiz - 1; + { + u_int k; + for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) { + cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf); + cpbufs[k].buf = cpbufs[k].stackbuf; + } + } + +#define PREPEND(CH) { \ + if (cp == cpbufs[0].buf) { \ + char *prev = cpbufs[0].buf; \ + emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \ + "format_tree"); \ + memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev, \ + cpbufs[0].bufsize); \ + cpbufs[0].bufsize *= 2; \ + if (prev != cpbufs[0].stackbuf) \ + free(prev); \ + cend = cpbufs[0].buf+cpbufs[0].bufsize; \ + } \ + *--cp = (CH); \ +} + /* * Icky problem. If the args make a nested call to printf/sprintf, * we end up clobbering the static variable `the_args'. Not good. @@ -927,7 +956,7 @@ check_pos: case 'i': need_format = FALSE; parse_next_arg(); - tmpval = force_number(arg); + tmpval = double_to_int(force_number(arg)); /* * ``The result of converting a zero value with a @@ -937,23 +966,29 @@ check_pos: goto pr_tail; if (tmpval < 0) { - if (tmpval < INTMAX_MIN) - goto out_of_range; + tmpval = -tmpval; sgn = TRUE; - uval = - (uintmax_t) (intmax_t) tmpval; } else { - /* Use !, so that NaNs are out of range. */ - if (! (tmpval <= UINTMAX_MAX)) - goto out_of_range; sgn = FALSE; - uval = (uintmax_t) tmpval; } ii = jj = 0; + while ((i = snprintf(cpbufs[1].buf, + cpbufs[1].bufsize, "%.0f", + tmpval)) > + cpbufs[1].bufsize) { + if (cpbufs[1].buf == cpbufs[1].stackbuf) + cpbufs[1].buf = NULL; + cpbufs[1].bufsize += ((i > cpbufs[1].bufsize) ? + i : cpbufs[1].bufsize); + erealloc(cpbufs[1].buf, char *, + cpbufs[1].bufsize, "format_tree"); + } + chp = &cpbufs[1].buf[i-1]; do { - *--cp = (char) ('0' + uval % 10); + PREPEND(*chp) #if ENABLE_NLS && defined(HAVE_LOCALE_H) if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) { - *--cp = loc.thousands_sep[0]; /* XXX - assumption it's one char */ + PREPEND(loc.thousands_sep[0]) /* XXX - assumption it's one char */ if (loc.grouping[ii+1] == 0) jj = 0; /* keep using current val in loc.grouping[ii] */ else if (loc.grouping[ii+1] == CHAR_MAX) @@ -964,19 +999,19 @@ check_pos: } } #endif - uval /= 10; - } while (uval > 0); + chp--; + } while (--i > 0); /* add more output digits to match the precision */ if (have_prec) { while (cend - cp < prec) - *--cp = '0'; + PREPEND('0') } if (sgn) - *--cp = '-'; + PREPEND('-') else if (signchar) - *--cp = signchar; + PREPEND(signchar) /* * When to fill with zeroes is of course not simple. * First: No zero fill if left-justifying. @@ -1052,10 +1087,10 @@ check_pos: ii = jj = 0; do { - *--cp = chbuf[uval % base]; + PREPEND(chbuf[uval % base]) #if ENABLE_NLS && defined(HAVE_LOCALE_H) if (base == 10 && quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) { - *--cp = loc.thousands_sep[0]; /* XXX --- assumption it's one char */ + PREPEND(loc.thousands_sep[0]) /* XXX --- assumption it's one char */ if (loc.grouping[ii+1] == 0) jj = 0; /* keep using current val in loc.grouping[ii] */ else if (loc.grouping[ii+1] == CHAR_MAX) @@ -1072,20 +1107,20 @@ check_pos: /* add more output digits to match the precision */ if (have_prec) { while (cend - cp < prec) - *--cp = '0'; + PREPEND('0') } if (alt && tmpval != 0) { if (base == 16) { - *--cp = cs1; - *--cp = '0'; + PREPEND(cs1) + PREPEND('0') if (fill != sp) { bchunk(cp, 2); cp += 2; fw -= 2; } } else if (base == 8) - *--cp = '0'; + PREPEND('0') } base = 0; if (prec > fw) @@ -1204,6 +1239,14 @@ check_pos: args_size = save_args_size; } + { + u_int k; + for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) { + if (cpbufs[k].buf != cpbufs[k].stackbuf) + free(cpbufs[k].buf); + } + } + return r; }