2 * gawkapi.c -- Implement the functions defined for gawkapi.h
6 * Copyright (C) 2012-2014 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
11 * GAWK is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
16 * GAWK is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28 static awk_bool_t node_to_awk_value(NODE *node, awk_value_t *result, awk_valtype_t wanted);
31 * api_get_argument --- get the count'th paramater, zero-based.
33 * Returns false if count is out of range, or if actual paramater
34 * does not match what is specified in wanted. In the latter
35 * case, fills in result->val_type with the actual type.
39 api_get_argument(awk_ext_id_t id, size_t count,
40 awk_valtype_t wanted, awk_value_t *result)
50 /* set up default result */
51 memset(result, 0, sizeof(*result));
52 result->val_type = AWK_UNDEFINED;
55 * Song and dance here. get_array_argument() and get_scalar_argument()
56 * will force a change in type of a parameter that is Node_var_new.
58 * Start by looking at the unadulterated argument as it was passed.
60 arg = get_argument(count);
64 /* if type is undefined */
65 if (arg->type == Node_var_new) {
66 if (wanted == AWK_UNDEFINED)
68 else if (wanted == AWK_ARRAY) {
75 /* at this point, we have real type */
76 if (arg->type == Node_var_array || arg->type == Node_array_ref) {
77 if (wanted != AWK_ARRAY && wanted != AWK_UNDEFINED)
84 /* get the array here */
85 arg = get_array_argument(count, false);
89 return node_to_awk_value(arg, result, wanted);
92 /* at this point we have a real type that is not an array */
93 arg = get_scalar_argument(count, false);
97 return node_to_awk_value(arg, result, wanted);
103 /* api_set_argument --- convert an argument to an array */
106 api_set_argument(awk_ext_id_t id,
108 awk_array_t new_array)
112 NODE *array = (NODE *) new_array;
116 if (array == NULL || array->type != Node_var_array)
119 if ( (arg = get_argument(count)) == NULL
120 || arg->type != Node_var_new)
123 arg = get_array_argument(count, false);
127 array->vname = arg->vname;
137 /* awk_value_to_node --- convert a value into a NODE */
140 awk_value_to_node(const awk_value_t *retval)
146 fatal(_("awk_value_to_node: received null retval"));
148 switch (retval->val_type) {
150 ext_ret_val = (NODE *) retval->array_cookie;
153 ext_ret_val = dupnode(Nnull_string);
156 ext_ret_val = make_number(retval->num_value);
159 ext_ret_val = make_str_node(retval->str_value.str,
160 retval->str_value.len, ALREADY_MALLOCED);
163 v = (NODE *) retval->scalar_cookie;
164 if (v->type != Node_var)
167 ext_ret_val = dupnode(v->var_value);
169 case AWK_VALUE_COOKIE:
170 ext_ret_val = dupnode((NODE *)(retval->value_cookie));
172 default: /* any invalid type */
180 /* Functions to print messages */
182 /* api_fatal --- print a fatal message and exit */
185 api_fatal(awk_ext_id_t id, const char *format, ...)
191 va_start(args, format);
192 err(true, _("fatal: "), format, args);
196 /* api_warning --- print a warning message and exit */
199 api_warning(awk_ext_id_t id, const char *format, ...)
205 va_start(args, format);
206 err(false, _("warning: "), format, args);
210 /* api_lintwarn --- print a lint warning message and exit if appropriate */
213 api_lintwarn(awk_ext_id_t id, const char *format, ...)
219 va_start(args, format);
220 if (lintwarn == r_fatal) {
221 err(true, _("fatal: "), format, args);
224 err(false, _("warning: "), format, args);
229 /* api_register_input_parser --- register an input_parser; for opening files read-only */
232 api_register_input_parser(awk_ext_id_t id, awk_input_parser_t *input_parser)
236 if (input_parser == NULL)
239 register_input_parser(input_parser);
242 /* api_register_output_wrapper --- egister an output wrapper, for writing files / two-way pipes */
244 static void api_register_output_wrapper(awk_ext_id_t id,
245 awk_output_wrapper_t *output_wrapper)
249 if (output_wrapper == NULL)
252 register_output_wrapper(output_wrapper);
255 /* api_register_two_way_processor --- register a processor for two way I/O */
258 api_register_two_way_processor(awk_ext_id_t id,
259 awk_two_way_processor_t *two_way_processor)
263 if (two_way_processor == NULL)
266 register_two_way_processor(two_way_processor);
269 /* Functions to update ERRNO */
271 /* api_update_ERRNO_int --- update ERRNO with an integer value */
274 api_update_ERRNO_int(awk_ext_id_t id, int errno_val)
278 update_ERRNO_int(errno_val);
281 /* api_update_ERRNO_string --- update ERRNO with a string value */
284 api_update_ERRNO_string(awk_ext_id_t id,
292 update_ERRNO_string(string);
295 /* api_unset_ERRNO --- unset ERRNO */
298 api_unset_ERRNO(awk_ext_id_t id)
306 /* api_add_ext_func --- add a function to the interpreter, returns true upon success */
309 api_add_ext_func(awk_ext_id_t id,
310 const char *namespace,
311 const awk_ext_func_t *func)
320 return make_builtin(func);
326 /* Stuff for exit handler - do it as linked list */
328 struct ext_exit_handler {
329 struct ext_exit_handler *next;
330 void (*funcp)(void *data, int exit_status);
333 static struct ext_exit_handler *list_head = NULL;
335 /* run_ext_exit_handlers --- run the extension exit handlers, LIFO order */
338 run_ext_exit_handlers(int exitval)
340 struct ext_exit_handler *p, *next;
342 for (p = list_head; p != NULL; p = next) {
344 p->funcp(p->arg0, exitval);
350 /* api_awk_atexit --- add an exit call back */
353 api_awk_atexit(awk_ext_id_t id,
354 void (*funcp)(void *data, int exit_status),
357 struct ext_exit_handler *p;
364 /* allocate memory */
365 emalloc(p, struct ext_exit_handler *, sizeof(struct ext_exit_handler), "api_awk_atexit");
371 /* add to linked list, LIFO order */
376 /* node_to_awk_value --- convert a node into a value for an extension */
379 node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted)
381 awk_bool_t ret = awk_false;
384 fatal(_("node_to_awk_value: received null node"));
387 fatal(_("node_to_awk_value: received null val"));
389 switch (node->type) {
390 case Node_var_new: /* undefined variable */
391 val->val_type = AWK_UNDEFINED;
392 if (wanted == AWK_UNDEFINED) {
399 if (wanted == AWK_SCALAR) {
400 val->val_type = AWK_SCALAR;
401 val->scalar_cookie = (void *) node;
406 node = node->var_value;
412 val->val_type = AWK_NUMBER;
414 (void) force_number(node);
415 if ((node->flags & NUMCUR) != 0) {
416 val->num_value = get_number_d(node);
422 val->val_type = AWK_STRING;
424 (void) force_string(node);
425 if ((node->flags & STRCUR) != 0) {
426 val->str_value.str = node->stptr;
427 val->str_value.len = node->stlen;
433 if ((node->flags & NUMBER) != 0) {
434 val->val_type = AWK_NUMBER;
435 } else if ((node->flags & STRING) != 0) {
436 val->val_type = AWK_STRING;
438 val->val_type = AWK_UNDEFINED;
443 /* return true and actual type for request of undefined */
444 if ((node->flags & NUMBER) != 0) {
445 val->val_type = AWK_NUMBER;
446 val->num_value = get_number_d(node);
448 } else if ((node->flags & STRING) != 0) {
449 val->val_type = AWK_STRING;
450 val->str_value.str = node->stptr;
451 val->str_value.len = node->stlen;
454 val->val_type = AWK_UNDEFINED;
458 case AWK_VALUE_COOKIE:
464 val->val_type = AWK_ARRAY;
465 if (wanted == AWK_ARRAY || wanted == AWK_UNDEFINED) {
466 val->array_cookie = node;
473 val->val_type = AWK_UNDEFINED;
482 * Symbol table access:
483 * - No access to special variables (NF, etc.)
484 * - One special exception: PROCINFO.
485 * - Use sym_update() to change a value, including from UNDEFINED
486 * to scalar or array.
489 * Lookup a variable, fills in value. No messing with the value
490 * returned. Returns false if the variable doesn't exist
491 * or the wrong type was requested.
492 * In the latter case, fills in vaule->val_type with the real type.
493 * Built-in variables (except PROCINFO) may not be accessed by an extension.
496 /* api_sym_lookup --- look up a symbol */
499 api_sym_lookup(awk_ext_id_t id,
501 awk_valtype_t wanted,
506 update_global_values(); /* make sure stuff like NF, NR, are up to date */
511 || (node = lookup(name)) == NULL)
514 if (is_off_limits_var(name)) /* a built-in variable */
515 node->flags |= NO_EXT_SET;
517 return node_to_awk_value(node, result, wanted);
520 /* api_sym_lookup_scalar --- retrieve the current value of a scalar */
523 api_sym_lookup_scalar(awk_ext_id_t id,
525 awk_valtype_t wanted,
528 NODE *node = (NODE *) cookie;
532 || node->type != Node_var)
535 update_global_values(); /* make sure stuff like NF, NR, are up to date */
537 return node_to_awk_value(node, result, wanted);
540 /* api_sym_update --- update a symbol's value, see gawkapi.h for semantics */
543 api_sym_update(awk_ext_id_t id,
555 switch (value->val_type) {
561 case AWK_VALUE_COOKIE:
565 /* fatal(_("api_sym_update: invalid value for type of new value (%d)"), value->val_type); */
572 /* new value to be installed */
573 if (value->val_type == AWK_ARRAY) {
574 array_node = awk_value_to_node(value);
575 node = install_symbol(estrdup((char *) name, strlen(name)),
577 array_node->vname = node->vname;
579 freenode(array_node);
580 value->array_cookie = node; /* pass new cookie back to extension */
582 /* regular variable */
583 node = install_symbol(estrdup((char *) name, strlen(name)),
585 node->var_value = awk_value_to_node(value);
592 * If we get here, then it exists already. Any valid type is
593 * OK except for AWK_ARRAY.
595 if ( (node->flags & NO_EXT_SET) != 0
596 || is_off_limits_var(name)) { /* most built-in vars not allowed */
597 node->flags |= NO_EXT_SET;
601 if ( value->val_type != AWK_ARRAY
602 && (node->type == Node_var || node->type == Node_var_new)) {
603 unref(node->var_value);
604 node->var_value = awk_value_to_node(value);
605 if (node->type == Node_var_new && value->val_type != AWK_UNDEFINED)
606 node->type = Node_var;
614 /* api_sym_update_scalar --- update a scalar cookie */
617 api_sym_update_scalar(awk_ext_id_t id,
621 NODE *node = (NODE *) cookie;
625 || node->type != Node_var
626 || (node->flags & NO_EXT_SET) != 0)
630 * Optimization: if valref is 1, and the new value is a string or
631 * a number, we can avoid calling unref and then making a new node
632 * by simply installing the new value. First, we follow the same
633 * recipe used by node.c:r_unref to wipe the current values, and then
634 * we copy the logic from r_make_number or make_str_node to install
637 switch (value->val_type) {
639 if (node->var_value->valref == 1 && ! do_mpfr) {
640 NODE *r = node->var_value;
643 if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
648 r->numbr = value->num_value;
649 r->flags = MALLOC|NUMBER|NUMCUR;
656 if (node->var_value->valref == 1) {
657 NODE *r = node->var_value;
660 if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
666 /* make_str_node(s, l, ALREADY_MALLOCED): */
668 r->flags = (MALLOC|STRING|STRCUR);
670 r->stptr = value->str_value.str;
671 r->stlen = value->str_value.len;
677 case AWK_VALUE_COOKIE:
680 default: /* AWK_ARRAY or invalid type */
684 /* do it the hard (slow) way */
685 unref(node->var_value);
686 node->var_value = awk_value_to_node(value);
691 * valid_subscript_type --- test if a type is allowed for an array subscript.
693 * Any scalar value is fine, so only AWK_ARRAY (or an invalid type) is illegal.
697 valid_subscript_type(awk_valtype_t valtype)
704 case AWK_VALUE_COOKIE:
706 default: /* AWK_ARRAY or an invalid type */
711 /* Array management */
713 * api_get_array_element --- teturn the value of an element - read only!
715 * Use set_array_element to change it.
719 api_get_array_element(awk_ext_id_t id,
720 awk_array_t a_cookie,
721 const awk_value_t *const index,
722 awk_valtype_t wanted,
725 NODE *array = (NODE *) a_cookie;
729 /* don't check for index len zero, null str is ok as index */
731 || array->type != Node_var_array
734 || ! valid_subscript_type(index->val_type))
737 subscript = awk_value_to_node(index);
739 /* if it doesn't exist, return false */
740 if (in_array(array, subscript) == NULL) {
745 aptr = assoc_lookup(array, subscript);
747 if (aptr == NULL) { /* can't happen */
754 return node_to_awk_value(*aptr, result, wanted);
758 * api_set_array_element --- change (or create) element in existing array
759 * with element->index and element->value.
763 api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie,
764 const awk_value_t *const index,
765 const awk_value_t *const value)
767 NODE *array = (NODE *)a_cookie;
772 /* don't check for index len zero, null str is ok as index */
774 || array->type != Node_var_array
775 || (array->flags & NO_EXT_SET) != 0
778 || ! valid_subscript_type(index->val_type))
781 tmp = awk_value_to_node(index);
782 aptr = assoc_lookup(array, tmp);
785 elem = *aptr = awk_value_to_node(value);
786 if (elem->type == Node_var_array) {
787 elem->parent_array = array;
788 elem->vname = estrdup(index->str_value.str,
789 index->str_value.len);
797 * remove_element --- remove an array element
798 * common code used by multiple functions
802 remove_element(NODE *array, NODE *subscript)
807 fatal(_("remove_element: received null array"));
809 if (subscript == NULL)
810 fatal(_("remove_element: received null subscript"));
812 val = in_array(array, subscript);
817 if (val->type == Node_var_array) {
819 /* cleared a sub-array, free Node_var_array */
825 (void) assoc_remove(array, subscript);
829 * api_del_array_element --- remove the element with the given index.
830 * Return success if removed or if element did not exist.
834 api_del_array_element(awk_ext_id_t id,
835 awk_array_t a_cookie, const awk_value_t* const index)
839 array = (NODE *) a_cookie;
841 || array->type != Node_var_array
842 || (array->flags & NO_EXT_SET) != 0
844 || ! valid_subscript_type(index->val_type))
847 sub = awk_value_to_node(index);
848 remove_element(array, sub);
855 * api_get_element_count --- retrieve total number of elements in array.
856 * Return false if some kind of error.
860 api_get_element_count(awk_ext_id_t id,
861 awk_array_t a_cookie, size_t *count)
863 NODE *node = (NODE *) a_cookie;
865 if (count == NULL || node == NULL || node->type != Node_var_array)
868 *count = node->table_size;
872 /* api_create_array --- create a new array cookie to which elements may be added */
875 api_create_array(awk_ext_id_t id)
880 memset(n, 0, sizeof(NODE));
883 return (awk_array_t) n;
886 /* api_clear_array --- clear out an array */
889 api_clear_array(awk_ext_id_t id, awk_array_t a_cookie)
891 NODE *node = (NODE *) a_cookie;
894 || node->type != Node_var_array
895 || (node->flags & NO_EXT_SET) != 0)
902 /* api_flatten_array --- flatten out an array so that it can be looped over easily. */
905 api_flatten_array(awk_ext_id_t id,
906 awk_array_t a_cookie,
907 awk_flat_array_t **data)
911 NODE *array = (NODE *) a_cookie;
915 || array->type != Node_var_array
916 || array->table_size == 0
920 alloc_size = sizeof(awk_flat_array_t) +
921 (array->table_size - 1) * sizeof(awk_element_t);
923 emalloc(*data, awk_flat_array_t *, alloc_size,
924 "api_flatten_array");
925 memset(*data, 0, alloc_size);
927 list = assoc_list(array, "@unsorted", ASORTI);
929 (*data)->opaque1 = array;
930 (*data)->opaque2 = list;
931 (*data)->count = array->table_size;
933 for (i = j = 0; i < 2 * array->table_size; i += 2, j++) {
937 value = list[i + 1]; /* number or string or subarray */
940 * Convert index and value to ext types. Force the
941 * index to be a string, since indices are always
942 * conceptually strings, regardless of internal optimizations
943 * to treat them as integers in some cases.
945 if (! node_to_awk_value(index,
946 & (*data)->elements[j].index, AWK_STRING)) {
947 fatal(_("api_flatten_array: could not convert index %d\n"),
950 if (! node_to_awk_value(value,
951 & (*data)->elements[j].value, AWK_UNDEFINED)) {
952 fatal(_("api_flatten_array: could not convert value %d\n"),
960 * api_release_flattened_array --- release array memory,
961 * delete any marked elements. Count must match what
962 * gawk thinks the size is.
966 api_release_flattened_array(awk_ext_id_t id,
967 awk_array_t a_cookie,
968 awk_flat_array_t *data)
970 NODE *array = a_cookie;
975 || array->type != Node_var_array
977 || array != (NODE *) data->opaque1
978 || data->count != array->table_size
979 || data->opaque2 == NULL)
982 list = (NODE **) data->opaque2;
984 /* free index nodes */
985 for (i = j = 0, k = 2 * array->table_size; i < k; i += 2, j++) {
986 /* Delete items flagged for delete. */
987 if ( (data->elements[j].flags & AWK_ELEMENT_DELETE) != 0
988 && (array->flags & NO_EXT_SET) == 0) {
989 remove_element(array, list[i]);
1000 /* api_create_value --- create a cached value */
1003 api_create_value(awk_ext_id_t id, awk_value_t *value,
1004 awk_value_cookie_t *result)
1006 if (value == NULL || result == NULL)
1009 switch (value->val_type) {
1014 /* reject anything other than a simple scalar */
1018 return (awk_bool_t) ((*result = awk_value_to_node(value)) != NULL);
1021 /* api_release_value --- release a cached value */
1024 api_release_value(awk_ext_id_t id, awk_value_cookie_t value)
1026 NODE *val = (NODE *) value;
1036 * Register a version string for this extension with gawk.
1039 struct version_info {
1040 const char *version;
1041 struct version_info *next;
1044 static struct version_info *vi_head;
1046 /* api_register_ext_version --- add an extension version string to the list */
1049 api_register_ext_version(awk_ext_id_t id, const char *version)
1051 struct version_info *info;
1053 if (version == NULL)
1058 emalloc(info, struct version_info *, sizeof(struct version_info), "register_ext_version");
1059 info->version = version;
1060 info->next = vi_head;
1064 /* the struct api */
1065 gawk_api_t api_impl = {
1067 GAWK_API_MAJOR_VERSION, /* major and minor versions */
1068 GAWK_API_MINOR_VERSION,
1069 { 0 }, /* do_flags */
1071 /* registration functions */
1073 api_register_input_parser,
1074 api_register_output_wrapper,
1075 api_register_two_way_processor,
1077 api_register_ext_version,
1079 /* message printing functions */
1084 /* updating ERRNO */
1085 api_update_ERRNO_int,
1086 api_update_ERRNO_string,
1089 /* Function arguments */
1093 /* Accessing and installing variables and constants */
1097 /* Accessing and modifying variables via scalar cookies */
1098 api_sym_lookup_scalar,
1099 api_sym_update_scalar,
1105 /* Array management */
1106 api_get_element_count,
1107 api_get_array_element,
1108 api_set_array_element,
1109 api_del_array_element,
1113 api_release_flattened_array,
1115 /* Memory allocation */
1122 /* init_ext_api --- init the extension API */
1127 /* force values to 1 / 0 */
1128 api_impl.do_flags[0] = (do_lint ? 1 : 0);
1129 api_impl.do_flags[1] = (do_traditional ? 1 : 0);
1130 api_impl.do_flags[2] = (do_profile ? 1 : 0);
1131 api_impl.do_flags[3] = (do_sandbox ? 1 : 0);
1132 api_impl.do_flags[4] = (do_debug ? 1 : 0);
1133 api_impl.do_flags[5] = (do_mpfr ? 1 : 0);
1136 /* update_ext_api --- update the variables in the API that can change */
1141 api_impl.do_flags[0] = (do_lint ? 1 : 0);
1144 /* print_ext_versions --- print the list */
1147 print_ext_versions(void)
1149 struct version_info *p;
1151 for (p = vi_head; p != NULL; p = p->next)
1152 printf("%s\n", p->version);