diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | extension/ChangeLog | 14 | ||||
-rw-r--r-- | extension/filefuncs.c | 5 | ||||
-rw-r--r-- | extension/fork.c | 15 | ||||
-rw-r--r-- | extension/ordchr.c | 9 | ||||
-rw-r--r-- | extension/readfile.c | 5 | ||||
-rw-r--r-- | extension/testext.c | 239 | ||||
-rw-r--r-- | extension/time.c | 9 | ||||
-rw-r--r-- | gawkapi.c | 113 | ||||
-rw-r--r-- | gawkapi.h | 14 |
10 files changed, 345 insertions, 93 deletions
@@ -1,3 +1,18 @@ +2012-06-17 Arnold D. Robbins <arnold@skeeve.com> + + API Work: + + * gawkapi.h (get_array_element): Remove `wanted' parameter. + (r_make_string): Comment the need for `api' and `ext_id' parameters. + * gawkapi.c (api_sym_update): Move checks to front. + Initial code for handling arrays. Still needs work. + (api_get_array_element): Implemented. + (api_set_array_element): Additional checking code. + (api_del_array_element): Implemented. + (api_create_array): Implemented. + (init_ext_api): Force do_xxx values to be 1 or 0. + (update_ext_api): Ditto. + 2012-06-12 Arnold D. Robbins <arnold@skeeve.com> API Work: diff --git a/extension/ChangeLog b/extension/ChangeLog index 09c88d31..2a62ff70 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,17 @@ +2012-06-17 Arnold D. Robbins <arnold@skeeve.com> + + * filefuncs.c (do_chdir, do_stat): Add assert(result != NULL). + * fork.c (do_fork, do_waitpid, do_wait): Ditto. + * ordchr.c (do_ord, do_chr): Ditto. + * readfile.c (do_readfile): Ditto. + * time.c (do_gettimeofday, do_sleep): Ditto. + * testext.c (All functions): Ditto. Clean up initial testing and use + make_number to make default return value up front. + (create_new_array, test_array_flatten): New functions. + (test_array_elem): Implemented. + (at_exit1): Don't printa actual pointer value: not portable. + (dl_load): Load up an array also. + 2012-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com> * time.c (RETURN): Remove obsolete define. diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 12f3acb6..433a0ea9 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -30,6 +30,7 @@ */ #include <stdio.h> +#include <assert.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -54,6 +55,8 @@ do_chdir(int nargs, awk_value_t *result) awk_value_t newdir; int ret = -1; + assert(result != NULL); + if (do_lint && nargs != 1) lintwarn(ext_id, "chdir: called with incorrect number of arguments, expecting 1"); @@ -264,6 +267,8 @@ do_stat(int nargs, awk_value_t *result) #endif /* S_IFDOOR */ }; + assert(result != NULL); + if (do_lint && nargs != 2) { lintwarn(ext_id, "stat: called with wrong number of arguments"); return make_number(-1, result); diff --git a/extension/fork.c b/extension/fork.c index 0c2e31d0..21a4145f 100644 --- a/extension/fork.c +++ b/extension/fork.c @@ -26,9 +26,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include <stdlib.h> #include <stdio.h> +#include <assert.h> #include <errno.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> @@ -67,7 +68,9 @@ do_fork(int nargs, awk_value_t *result) { int ret = -1; - if (do_lint && nargs > 0) + assert(result != NULL); + + if (do_lint && nargs > 0) lintwarn(ext_id, "fork: called with too many arguments"); ret = fork(); @@ -102,7 +105,9 @@ do_waitpid(int nargs, awk_value_t *result) int ret = -1; int options = 0; - if (do_lint && nargs > 1) + assert(result != NULL); + + if (do_lint && nargs > 1) lintwarn(ext_id, "waitpid: called with too many arguments"); if (get_argument(0, AWK_NUMBER, &pid)) { @@ -125,7 +130,9 @@ do_wait(int nargs, awk_value_t *result) { int ret; - if (do_lint && nargs > 0) + assert(result != NULL); + + if (do_lint && nargs > 0) lintwarn(ext_id, "wait: called with too many arguments"); ret = wait(NULL); diff --git a/extension/ordchr.c b/extension/ordchr.c index dc02479a..ba29d132 100644 --- a/extension/ordchr.c +++ b/extension/ordchr.c @@ -30,6 +30,7 @@ */ #include <stdio.h> +#include <assert.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -53,7 +54,9 @@ do_ord(int nargs, awk_value_t *result) awk_value_t str; double ret = -1; - if (do_lint && nargs > 1) + assert(result != NULL); + + if (do_lint && nargs > 1) lintwarn(ext_id, "ord: called with too many arguments"); if (get_argument(0, AWK_STRING, & str)) { @@ -77,7 +80,9 @@ do_chr(int nargs, awk_value_t *result) str[0] = str[1] = '\0'; - if (do_lint && nargs > 1) + assert(result != NULL); + + if (do_lint && nargs > 1) lintwarn(ext_id, "chr: called with too many arguments"); if (get_argument(0, AWK_NUMBER, & num)) { diff --git a/extension/readfile.c b/extension/readfile.c index 166bb8fb..89723036 100644 --- a/extension/readfile.c +++ b/extension/readfile.c @@ -32,6 +32,7 @@ */ #include <stdio.h> +#include <assert.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> @@ -63,7 +64,9 @@ do_readfile(int nargs, awk_value_t *result) char *text; int fd; - if (do_lint && nargs > 1) + assert(result != NULL); + + if (do_lint && nargs > 1) lintwarn(ext_id, "readfile: called with too many arguments"); if (get_argument(0, AWK_STRING, &filename)) { diff --git a/extension/testext.c b/extension/testext.c index fa8dbf64..697913fa 100644 --- a/extension/testext.c +++ b/extension/testext.c @@ -25,6 +25,7 @@ */ #include <stdio.h> +#include <assert.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -58,6 +59,7 @@ int plugin_is_GPL_compatible; static awk_value_t * dump_procinfo(int nargs, awk_value_t *result) { + assert(result != NULL); /* get PROCINFO as flat array and print it */ return result; } @@ -77,16 +79,19 @@ var_test(int nargs, awk_value_t *result) awk_value_t value, value2; awk_value_t *valp; - if (nargs != 1 || result == NULL) { - printf("var_test: nargs not right (%d should be 1) or result == NULL\n", nargs); - return NULL; + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 1) { + printf("var_test: nargs not right (%d should be 1)\n", nargs); + goto out; } /* look up a reserved variable - should fail */ if (sym_lookup("ARGC", AWK_NUMBER, & value)) printf("var_test: sym_lookup of ARGC failed - got a value!\n"); else - printf("var_test: sym_lookup of ARGC passed\n"); + printf("var_test: sym_lookup of ARGC passed - did not get a value\n"); /* look up variable whose name is passed in, should pass */ if (get_argument(0, AWK_STRING, & value)) { @@ -98,20 +103,19 @@ var_test(int nargs, awk_value_t *result) printf("var_test: sym_update(\"%s\") succeeded\n", value.str_value.str); } else { printf("var_test: sym_update(\"%s\") failed\n", value.str_value.str); - return NULL; + goto out; } } else { printf("var_test: sym_lookup(\"%s\") failed\n", value.str_value.str); - return NULL; + goto out; } } else { printf("var_test: get_argument() failed\n"); - return NULL; + goto out; } - result->val_type = AWK_NUMBER; - result->num_value = 1.0; - + make_number(1.0, result); +out: return result; } @@ -125,16 +129,18 @@ BEGIN { static awk_value_t * test_errno(int nargs, awk_value_t *result) { - if (nargs != 0 || result == NULL) { - printf("test_errno: nargs not right (%d should be 0) or result == NULL\n", nargs); - return NULL; + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 0) { + printf("test_errno: nargs not right (%d should be 0)\n", nargs); + goto out; } update_ERRNO_int(ECHILD); - result->val_type = AWK_NUMBER; - result->num_value = 1.0; - + make_number(1.0, result); +out: return result; } @@ -155,20 +161,23 @@ test_array_size(int nargs, awk_value_t *result) awk_value_t value; size_t count = 0; - if (nargs != 1 || result == NULL) { - printf("test_array_size: nargs not right (%d should be 0) or result == NULL\n", nargs); - return NULL; + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 1) { + printf("test_array_size: nargs not right (%d should be 1)\n", nargs); + goto out; } /* get element count and print it; should match length(array) from awk script */ if (! get_argument(0, AWK_ARRAY, & value)) { printf("test_array_size: get_argument failed\n"); - return NULL; + goto out; } if (! get_element_count(value.array_cookie, & count)) { printf("test_array_size: get_element_count failed\n"); - return NULL; + goto out; } printf("test_array_size: incoming size is %lu\n", (unsigned long) count); @@ -176,37 +185,103 @@ test_array_size(int nargs, awk_value_t *result) /* clear array - length(array) should then go to zero in script */ if (! clear_array(value.array_cookie)) { printf("test_array_size: clear_array failed\n"); - return NULL; + goto out; } - result->val_type = AWK_NUMBER; - result->num_value = 1.0; + make_number(1.0, result); +out: return result; } /* -#BEGIN { -# n = split("one two three four five six", test_array2) -# ret = test_array_elem(test_array2, "3") -# printf "test_array_elem() returned %d, test_array2[3] = %g\n", ret, test_array2[3] -# if ("5" in test_array2) -# printf "error: test_array_elem did not remove element \"5\"\n" -# else -# printf "test_array_elem did remove element \"5\"\n" -#} +BEGIN { + n = split("one two three four five six", test_array2) + ret = test_array_elem(test_array2, "3") + printf "test_array_elem() returned %d, test_array2[3] = %g\n", ret, test_array2[3] + if ("5" in test_array2) + printf "error: test_array_elem did not remove element \"5\"\n" + else + printf "test_array_elem did remove element \"5\"\n" + if ("7" in test_array2) + printf "test_array_elem added element \"7\" --> %s\n", test_array2[7] + else + printf "test_array_elem did not add element \"7\"\n" +} */ static awk_value_t * test_array_elem(int nargs, awk_value_t *result) { - if (nargs != 2 || result == NULL) { - printf("test_array_elem: nargs not right (%d should be 2) or result == NULL\n", nargs); - return NULL; + awk_value_t array, index, value; + awk_element_t element; + + memset(& element, 0, sizeof(element)); + make_number(0.0, result); /* default return until full success */ + + assert(result != NULL); + + if (nargs != 2) { + printf("test_array_elem: nargs not right (%d should be 2)\n", nargs); + goto out; } + /* look up an array element and print the value */ + if (! get_argument(0, AWK_ARRAY, & array)) { + printf("test_array_elem: get_argument 0 (array) failed\n"); + goto out; + } + if (! get_argument(1, AWK_STRING, & index)) { + printf("test_array_elem: get_argument 1 (index) failed\n"); + goto out; + } + if (! get_array_element(array.array_cookie, & index, & value)) { + printf("test_array_elem: get_array_element failed\n"); + goto out; + } + printf("test_array_elem: a[\"%.*s\"] = ", (int) index.str_value.len, + index.str_value.str); + switch (value.val_type) { + case AWK_UNDEFINED: + printf("<undefined>\n"); + break; + case AWK_ARRAY: + printf("<array>\n"); + break; + case AWK_STRING: + printf("\"%.*s\"\n", (int) value.str_value.len, value.str_value.str); + break; + case AWK_NUMBER: + printf("%g\n", value.num_value); + break; + } + /* change the element - "3" */ + element.index = index.str_value; + (void) make_number(42.0, & element.value); + if (! set_array_element(array.array_cookie, & element)) { + printf("test_array_elem: set_array_element failed\n"); + goto out; + } + /* delete another element - "5" */ + (void) make_string("5", 1, & index); + if (! del_array_element(array.array_cookie, & index)) { + printf("test_array_elem: del_array_element failed\n"); + goto out; + } + + /* add a new element - "7" */ + (void) make_string("7", 1, & index); + element.index = index.str_value; + (void) make_string("seven", 5, & element.value); + if (! set_array_element(array.array_cookie, & element)) { + printf("test_array_elem: set_array_element failed\n"); + goto out; + } + /* change and deletion should be reflected in awk script */ + make_number(1.0, result); +out: return result; } @@ -224,19 +299,86 @@ BEGIN { static awk_value_t * print_do_lint(int nargs, awk_value_t *result) { - if (nargs != 0 || result == NULL) { - printf("print_do_lint: nargs not right (%d should be 0) or result == NULL\n", nargs); - return NULL; + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 0) { + printf("print_do_lint: nargs not right (%d should be 0)\n", nargs); + goto out; } printf("print_do_lint: lint = %d\n", do_lint); - result->val_type = AWK_NUMBER; - result->num_value = 1.0; + make_number(1.0, result); +out: return result; } +/* +#BEGIN { +# n = split("one two three four five six", test_array3) +# ret = test_array_flatten(test_array3) +# printf "test_array_flatten() returned %d\n", ret +# if ("3" in test_array3) +# printf "error: test_array_flatten() did not remove element \"3\"\n" +# else +# printf "test_array_flatten() did remove element \"3\"\n" +#} +*/ + +static awk_value_t * +test_array_flatten(int nargs, awk_value_t *result) +{ + assert(result != NULL); + make_number(0.0, result); + + if (nargs != 1) { + printf("test_array_flatten: nargs not right (%d should be 1)\n", nargs); + goto out; + } + + /* FIXME: CODE HERE */ + + make_number(1.0, result); + +out: + return result; +} + +static void +create_new_array() +{ + awk_element_t element; + awk_array_t a_cookie; + awk_value_t index; + awk_value_t value; + + a_cookie = create_array(); + + (void) make_string("hello", 6, & index); + element.index = index.str_value; + (void) make_string("world", 5, & element.value); + if (! set_array_element(a_cookie, & element)) { + printf("create_new_array:%d: set_array_element failed\n", __LINE__); + return; + } + + (void) make_string("answer", 6, & index); + element.index = index.str_value; + (void) make_number(42.0, & element.value); + if (! set_array_element(a_cookie, & element)) { + printf("create_new_array:%d: set_array_element failed\n", __LINE__); + return; + } + + value.val_type = AWK_ARRAY; + value.array_cookie = a_cookie; + + if (! sym_update("new_array", & value)) + printf("create_new_array: sym_update(\"new_array\") failed!\n"); +} + static void at_exit0(void *data, int exit_status) { printf("at_exit0 called (should be third):"); @@ -251,13 +393,15 @@ static void at_exit0(void *data, int exit_status) static int data_for_1 = 0xDeadBeef; static void at_exit1(void *data, int exit_status) { + int *data_p = (int *) data; + printf("at_exit1 called (should be second):"); if (data) { - printf(" data = %p", data); if (data == & data_for_1) printf(" (data is & data_for_1),"); else printf(" (data is NOT & data_for_1),"); + printf(" data value = %#x,", *data_p); } else printf(" data = NULL,"); printf(" exit_status = %d\n", exit_status); @@ -279,11 +423,10 @@ static awk_ext_func_t func_table[] = { { "test_errno", test_errno, 0 }, { "test_array_size", test_array_size, 1 }, { "test_array_elem", test_array_elem, 2 }, + { "test_array_flatten", test_array_flatten, 1 }, { "print_do_lint", print_do_lint, 0 }, }; - - int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) { size_t i, j; @@ -321,15 +464,19 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id) BEGIN { printf("answer_num = %g\n", answer_num); printf("message_string = %s\n", message_string); + for (i in new_array) + printf("new_array[\"%s\"] = \"%s\"\n", i, new_array[i]) } */ /* install some variables */ if (! sym_update("answer_num", make_number(42, & value))) - printf("textext: sym_update(\"answer_num\") failed!\n"); + printf("testext: sym_update(\"answer_num\") failed!\n"); if (! sym_update("message_string", dup_string(message, strlen(message), & value))) - printf("textext: sym_update(\"answer_num\") failed!\n"); + printf("testext: sym_update(\"answer_num\") failed!\n"); + + create_new_array(); return (errors == 0); } diff --git a/extension/time.c b/extension/time.c index ba8578c3..2024510c 100644 --- a/extension/time.c +++ b/extension/time.c @@ -26,6 +26,7 @@ */ #include <stdio.h> +#include <assert.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -61,7 +62,9 @@ do_gettimeofday(int nargs, awk_value_t *result) { double curtime; - if (do_lint && nargs > 0) + assert(result != NULL); + + if (do_lint && nargs > 0) lintwarn(ext_id, "gettimeofday: ignoring arguments"); #if defined(HAVE_GETTIMEOFDAY) @@ -111,7 +114,9 @@ do_sleep(int nargs, awk_value_t *result) double secs; int rc; - if (do_lint && nargs > 1) + assert(result != NULL); + + if (do_lint && nargs > 1) lintwarn(ext_id, "sleep: called with too many arguments"); if (! get_argument(0, AWK_NUMBER, &num)) { @@ -75,7 +75,8 @@ awk_value_to_node(const awk_value_t *retval) } else if (retval->val_type == AWK_NUMBER) { ext_ret_val = make_number(retval->num_value); } else { - ext_ret_val = make_string(retval->str_value.str, retval->str_value.len); + ext_ret_val = make_string(retval->str_value.str, + retval->str_value.len); } return ext_ret_val; @@ -366,36 +367,46 @@ static awk_bool_t api_sym_update(awk_ext_id_t id, const char *name, awk_value_t *value) { NODE *node; + NODE *array_node; + + if ( name == NULL + || *name == '\0' + || is_off_limits_var(name) /* most built-in vars not allowed */ + || value == NULL) + return false; switch (value->val_type) { case AWK_NUMBER: case AWK_STRING: case AWK_UNDEFINED: - break; - case AWK_ARRAY: - return false; + break; default: /* fatal(_("api_sym_update: invalid value for type of new value (%d)"), value->val_type); */ return false; } - if ( name == NULL - || *name == '\0' - || is_off_limits_var(name) /* most built-in vars not allowed */ - || value == NULL) - return false; - node = lookup(name); if (node == NULL) { /* new value to be installed */ - node = install_symbol((char *) name, Node_var); + if (value->val_type == AWK_ARRAY) { + array_node = awk_value_to_node(value); + node = install_symbol(estrdup((char *) name, strlen(name)), + Node_var_array); + array_node->vname = node->vname; + *node = *array_node; + freenode(array_node); + } else { + /* regular variable */ + node = install_symbol(estrdup((char *) name, strlen(name)), + Node_var); + unref(node->var_value); + node->var_value = awk_value_to_node(value); + } } - unref(node->var_value); - - node->var_value = awk_value_to_node(value); + /* FIXME: Handle case where it exists already */ return true; } @@ -407,25 +418,30 @@ api_sym_update(awk_ext_id_t id, const char *name, awk_value_t *value) */ static awk_bool_t api_get_array_element(awk_ext_id_t id, - awk_array_t a_cookie, const awk_value_t *const index, - awk_valtype_t wanted, awk_value_t *result) + awk_array_t a_cookie, + const awk_value_t *const index, + awk_value_t *result) { - NODE *array; + NODE *array = (NODE *) a_cookie; NODE *subscript; + NODE **aptr; /* don't check for index len zero, null str is ok as index */ - if ( a_cookie == NULL + if ( array == NULL + || array->type != Node_var_array || result == NULL || index == NULL || index->val_type != AWK_STRING || index->str_value.str == NULL) return false; - array = (NODE *) a_cookie; subscript = awk_value_to_node(index); - /* FIXME: write rest of code */ + aptr = assoc_lookup(array, subscript); + unref(subscript); + if (aptr == NULL) + return false; - return true; /* for now */ + return node_to_awk_value(*aptr, result, AWK_UNDEFINED); } /* @@ -441,7 +457,8 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie, NODE **aptr; /* don't check for index len zero, null str is ok as index */ - if ( a_cookie == NULL + if ( array == NULL + || array->type != Node_var_array || element == NULL || element->index.str == NULL) return false; @@ -451,6 +468,7 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie, unref(tmp); unref(*aptr); *aptr = awk_value_to_node(& element->value); + return true; } @@ -462,7 +480,33 @@ static awk_bool_t api_del_array_element(awk_ext_id_t id, awk_array_t a_cookie, const awk_value_t* const index) { - return true; /* for now */ + NODE *array, *sub, *val; + + array = (NODE *) a_cookie; + if ( array == NULL + || array->type != Node_var_array + || index == NULL + || index->val_type != AWK_STRING) + return false; + + sub = awk_value_to_node(index); + val = in_array(array, sub); + + if (val == NULL) + return false; + + if (val->type == Node_var_array) { + assoc_clear(val); + /* cleared a sub-array, free Node_var_array */ + efree(val->vname); + freenode(val); + } else + unref(val); + + (void) assoc_remove(array, sub); + unref(sub); + + return true; } /* @@ -486,7 +530,13 @@ api_get_element_count(awk_ext_id_t id, static awk_array_t api_create_array(awk_ext_id_t id) { - return NULL; /* for now */ + NODE *n; + + getnode(n); + memset(n, 0, sizeof(NODE)); + init_array(n); + + return (awk_array_t) n; } /* Clear out an array */ @@ -564,12 +614,13 @@ gawk_api_t api_impl = { void init_ext_api() { - api_impl.do_flags[0] = do_lint; - api_impl.do_flags[1] = do_traditional; - api_impl.do_flags[2] = do_profile; - api_impl.do_flags[3] = do_sandbox; - api_impl.do_flags[4] = do_debug; - api_impl.do_flags[5] = do_mpfr; + /* force values to 1 / 0 */ + api_impl.do_flags[0] = (do_lint ? 1 : 0); + api_impl.do_flags[1] = (do_traditional ? 1 : 0); + api_impl.do_flags[2] = (do_profile ? 1 : 0); + api_impl.do_flags[3] = (do_sandbox ? 1 : 0); + api_impl.do_flags[4] = (do_debug ? 1 : 0); + api_impl.do_flags[5] = (do_mpfr ? 1 : 0); } /* update_ext_api --- update the variables in the API that can change */ @@ -577,5 +628,5 @@ init_ext_api() void update_ext_api() { - api_impl.do_flags[0] = do_lint; + api_impl.do_flags[0] = (do_lint ? 1 : 0); } @@ -287,8 +287,8 @@ typedef struct gawk_api { * and sym_lookup. */ awk_bool_t (*get_array_element)(awk_ext_id_t id, - awk_array_t a_cookie, const awk_value_t *const index, - awk_valtype_t wanted, + awk_array_t a_cookie, + const awk_value_t *const index, awk_value_t *result); /* @@ -364,12 +364,12 @@ typedef struct gawk_api { #define add_ext_func(func, ns) (api->add_ext_func(ext_id, func, ns)) #define awk_atexit(funcp, arg0) (api->awk_atexit(ext_id, funcp, arg0)) -#define sym_lookup(name, result, wanted) (api->sym_lookup(ext_id, name, result, wanted)) +#define sym_lookup(name, wanted, result) (api->sym_lookup(ext_id, name, wanted, result)) #define sym_update(name, value) \ (api->sym_update(ext_id, name, value)) -#define get_array_element(array, element, result, wanted) \ - (api->get_array_element(ext_id, array, element, result, wanted)) +#define get_array_element(array, index, result) \ + (api->get_array_element(ext_id, array, index, result)) #define set_array_element(array, element) \ (api->set_array_element(ext_id, array, element)) @@ -401,8 +401,8 @@ typedef struct gawk_api { /* r_make_string --- make a string value in result from the passed-in string */ static inline awk_value_t * -r_make_string(const gawk_api_t *api, - awk_ext_id_t *ext_id, +r_make_string(const gawk_api_t *api, /* needed for emalloc */ + awk_ext_id_t *ext_id, /* ditto */ const char *string, size_t length, awk_bool_t duplicate, |