diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:52:31 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:52:31 +0300 |
commit | 3ba50a15ebd976f7a88393e2e45dc14b6478b9a9 (patch) | |
tree | 6a6bbe6bed1141051fefe94b2d39eacd4854235a /node.c | |
parent | 6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f (diff) | |
download | gawk-3ba50a15ebd976f7a88393e2e45dc14b6478b9a9.tar.gz |
Move to gawk-3.1.7.gawk-3.1.7
Diffstat (limited to 'node.c')
-rw-r--r-- | node.c | 119 |
1 files changed, 90 insertions, 29 deletions
@@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1986, 1988, 1989, 1991-2001, 2003-2007 the Free Software Foundation, Inc. + * Copyright (C) 1986, 1988, 1989, 1991-2001, 2003-2009 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -156,18 +156,35 @@ finish: } +/* + * the following lookup table is used as an optimization in force_string + * (more complicated) variations on this theme didn't seem to pay off, but + * systematic testing might be in order at some point + */ +static const char *values[] = { + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", +}; +#define NVAL (sizeof(values)/sizeof(values[0])) + /* format_val --- format a numeric value based on format */ NODE * format_val(const char *format, int index, register NODE *s) { + char buf[BUFSIZ]; + register char *sp = buf; double val; char *orig, *trans, save; - NODE *dummy, *r; - unsigned short oflags; - extern NODE **fmt_list; /* declared in eval.c */ - if (! do_traditional && (s->flags & INTLSTR) != 0) { save = s->stptr[s->stlen]; s->stptr[s->stlen] = '\0'; @@ -185,32 +202,71 @@ format_val(const char *format, int index, register NODE *s) * can use sprintf("%ld", val) on it, always format it ourselves. * The only thing to worry about is that integral values always * format as integers. %.0f does that very well. + * + * 6/2008: Would that things were so simple. Always using %.0f + * imposes a notable performance penalty for applications that + * do a lot of conversion of integers to strings. So, we reinstate + * the old code, but use %.0f for integral values that are outside + * the range of a long. This seems a reasonable compromise. */ - val = double_to_int(s->numbr); - - /* create dummy node for a sole use of format_tree */ - getnode(dummy); - dummy->type = Node_expression_list; - dummy->lnode = s; - dummy->rnode = NULL; - oflags = s->flags; - s->flags |= PERM; /* prevent from freeing by format_tree() */ - if (val == s->numbr) { - r = format_tree("%.0f", 4, dummy, 2); - s->stfmt = -1; + /* not an integral value, or out of range */ + if ((val = double_to_int(s->numbr)) != s->numbr + || val < LONG_MIN || val > LONG_MAX) { + /* + * Once upon a time, if GFMT_WORKAROUND wasn't defined, + * we just blindly did this: + * sprintf(sp, format, s->numbr); + * s->stlen = strlen(sp); + * s->stfmt = (char) index; + * but that's no good if, e.g., OFMT is %s. So we punt, + * and just always format the value ourselves. + */ + + NODE *dummy, *r; + unsigned short oflags; + extern NODE **fmt_list; /* declared in eval.c */ + + /* create dummy node for a sole use of format_tree */ + getnode(dummy); + dummy->type = Node_expression_list; + dummy->lnode = s; + dummy->rnode = NULL; + oflags = s->flags; + s->flags |= PERM; /* prevent from freeing by format_tree() */ + if (val == s->numbr) { + /* integral value, but outside range of %ld, use %.0f */ + r = format_tree("%.0f", 4, dummy, 2); + s->stfmt = -1; + } else { + r = format_tree(format, fmt_list[index]->stlen, dummy, 2); + s->stfmt = (char) index; + } + s->flags = oflags; + s->stlen = r->stlen; + if ((s->flags & STRCUR) != 0) + free(s->stptr); + s->stptr = r->stptr; + freenode(r); /* Do not free_temp(r)! We want */ + freenode(dummy); /* to keep s->stptr == r->stpr. */ + + goto no_malloc; } else { - r = format_tree(format, fmt_list[index]->stlen, dummy, 2); - s->stfmt = (char) index; + /* integral value */ + /* force conversion to long only once */ + register long num = (long) val; + if (num < NVAL && num >= 0) { + sp = (char *) values[num]; + s->stlen = 1; + } else { + (void) sprintf(sp, "%ld", num); + s->stlen = strlen(sp); + } + s->stfmt = -1; } - s->flags = oflags; - s->stlen = r->stlen; - if ((s->flags & STRCUR) != 0) - free(s->stptr); - s->stptr = r->stptr; - freenode(r); /* Do not free_temp(r)! We want */ - freenode(dummy); /* to keep s->stptr == r->stpr. */ - + emalloc(s->stptr, char *, s->stlen + 2, "format_val"); + memcpy(s->stptr, sp, s->stlen+1); +no_malloc: s->stref = 1; s->flags |= STRCUR; free_wstr(s); @@ -539,6 +595,8 @@ parse_escape(const char **string_ptr) register int c = *(*string_ptr)++; register int i; register int count; + int j; + const char *start; if (do_lint_old) { switch (c) { @@ -605,8 +663,9 @@ parse_escape(const char **string_ptr) warning(_("no hex digits in `\\x' escape sequence")); return ('x'); } - i = 0; - for (;;) { + i = j = 0; + start = *string_ptr; + for (;; j++) { /* do outside test to avoid multiple side effects */ c = *(*string_ptr)++; if (ISXDIGIT(c)) { @@ -622,6 +681,8 @@ parse_escape(const char **string_ptr) break; } } + if (do_lint && j > 2) + lintwarn(_("hex escape \\x%.*s of %d characters probably not interpreted the way you expect"), j, start, j); return i; case '\\': case '"': |