summaryrefslogtreecommitdiff
path: root/node.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-16 14:52:31 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-16 14:52:31 +0300
commit3ba50a15ebd976f7a88393e2e45dc14b6478b9a9 (patch)
tree6a6bbe6bed1141051fefe94b2d39eacd4854235a /node.c
parent6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f (diff)
downloadgawk-3ba50a15ebd976f7a88393e2e45dc14b6478b9a9.tar.gz
Move to gawk-3.1.7.gawk-3.1.7
Diffstat (limited to 'node.c')
-rw-r--r--node.c119
1 files changed, 90 insertions, 29 deletions
diff --git a/node.c b/node.c
index 0a7be425..e4d9079a 100644
--- a/node.c
+++ b/node.c
@@ -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 '"':