aboutsummaryrefslogtreecommitdiffstats
path: root/gawkapi.c
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2016-07-08 15:26:00 -0400
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2016-07-08 15:26:00 -0400
commitc86137f472fdf876c2c223c8d99f673f477b7554 (patch)
tree7ed0e172eaa8d4f831a2d59287547f63f1e71dee /gawkapi.c
parent4a0f74139fb702a14c2e6782fb1965245e4f9d2f (diff)
downloadegawk-c86137f472fdf876c2c223c8d99f673f477b7554.tar.gz
egawk-c86137f472fdf876c2c223c8d99f673f477b7554.tar.bz2
egawk-c86137f472fdf876c2c223c8d99f673f477b7554.zip
Optimization: support unterminated field strings inside gawk, but make terminated copies for the API.
Diffstat (limited to 'gawkapi.c')
-rw-r--r--gawkapi.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/gawkapi.c b/gawkapi.c
index afefa4f6..97825a30 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -391,6 +391,52 @@ api_awk_atexit(awk_ext_id_t id,
list_head = p;
}
+static struct {
+ char **strings;
+ size_t i, size;
+} scopy;
+
+void
+free_api_string_copies()
+{
+ size_t i;
+
+ for (i = 0; i < scopy.i; i++)
+ free(scopy.strings[i]);
+ scopy.i = 0;
+}
+
+/* return a node string with nul termination */
+
+static inline void
+assign_string(NODE *node, awk_value_t *val)
+{
+ val->val_type = AWK_STRING;
+ if (node->stptr[node->stlen] != '\0') {
+ /*
+ * This is an unterminated field string, so make a copy.
+ * This should happen only for $n where n > 0 and n < NF.
+ */
+ char *s;
+ assert((node->flags & MALLOC) == 0);
+ if (scopy.i == scopy.size) {
+ /* expand list */
+ if (scopy.size == 0)
+ scopy.size = 8; /* initial size */
+ else
+ scopy.size *= 2;
+ erealloc(scopy.strings, char **, scopy.size * sizeof(char *), "assign_string");
+ }
+ emalloc(s, char *, node->stlen + 1, "assign_string");
+ memcpy(s, node->stptr, node->stlen);
+ s[node->stlen] = '\0';
+ val->str_value.str = scopy.strings[scopy.i++] = s;
+ }
+ else
+ val->str_value.str = node->stptr;
+ val->str_value.len = node->stlen;
+}
+
/* node_to_awk_value --- convert a node into a value for an extension */
static awk_bool_t
@@ -435,12 +481,8 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted)
break;
case AWK_STRING:
- val->val_type = AWK_STRING;
-
(void) force_string(node);
- val->str_value.str = node->stptr;
- val->str_value.len = node->stlen;
- assert(val->str_value.str[val->str_value.len] == '\0');
+ assign_string(node, val);
ret = awk_true;
break;
@@ -466,10 +508,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted)
val->num_value = get_number_d(node);
ret = awk_true;
} else if ((node->flags & STRING) != 0) {
- val->val_type = AWK_STRING;
- val->str_value.str = node->stptr;
- val->str_value.len = node->stlen;
- assert(val->str_value.str[val->str_value.len] == '\0');
+ assign_string(node, val);
ret = awk_true;
} else
val->val_type = AWK_UNDEFINED;