(root)/
gawk-5.2.2/
ext.c
       1  /*
       2   * ext.c - Builtin function that links external gawk functions and related
       3   *	   utilities.
       4   *
       5   * Christos Zoulas, Thu Jun 29 17:40:41 EDT 1995
       6   * Arnold Robbins, update for 3.1, Mon Nov 23 12:53:39 EST 1998
       7   */
       8  
       9  /*
      10   * Copyright (C) 1995 - 2001, 2003-2014, 2016-2020, 2022,
      11   * the Free Software Foundation, Inc.
      12   *
      13   * This file is part of GAWK, the GNU implementation of the
      14   * AWK Programming Language.
      15   *
      16   * GAWK is free software; you can redistribute it and/or modify
      17   * it under the terms of the GNU General Public License as published by
      18   * the Free Software Foundation; either version 3 of the License, or
      19   * (at your option) any later version.
      20   *
      21   * GAWK is distributed in the hope that it will be useful,
      22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24   * GNU General Public License for more details.
      25   *
      26   * You should have received a copy of the GNU General Public License
      27   * along with this program; if not, write to the Free Software
      28   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
      29   */
      30  
      31  #include "awk.h"
      32  extern SRCFILE *srcfiles;
      33  
      34  #ifdef DYNAMIC
      35  
      36  #include <dlfcn.h>
      37  
      38  #define INIT_FUNC	"dl_load"
      39  
      40  /* load_ext --- load an external library */
      41  
      42  void
      43  load_ext(const char *lib_name)
      44  {
      45  	int (*install_func)(const gawk_api_t *const, awk_ext_id_t);
      46  	void *dl;
      47  	int flags = RTLD_LAZY;
      48  	int *gpl_compat;
      49  
      50  	if (do_sandbox)
      51  		fatal(_("extensions are not allowed in sandbox mode"));
      52  
      53  	if (do_traditional || do_posix)
      54  		fatal(_("-l / @load are gawk extensions"));
      55  
      56  	if (lib_name == NULL)
      57  		fatal(_("load_ext: received NULL lib_name"));
      58  
      59  	if ((dl = dlopen(lib_name, flags)) == NULL)
      60  		fatal(_("load_ext: cannot open library `%s': %s"), lib_name,
      61  		      dlerror());
      62  
      63  	/* Per the GNU Coding standards */
      64  	gpl_compat = (int *) dlsym(dl, "plugin_is_GPL_compatible");
      65  	if (gpl_compat == NULL)
      66  		fatal(_("load_ext: library `%s': does not define `plugin_is_GPL_compatible': %s"),
      67  				lib_name, dlerror());
      68  
      69  	install_func = (int (*)(const gawk_api_t *const, awk_ext_id_t))
      70  				dlsym(dl, INIT_FUNC);
      71  	if (install_func == NULL)
      72  		fatal(_("load_ext: library `%s': cannot call function `%s': %s"),
      73  				lib_name, INIT_FUNC, dlerror());
      74  
      75  	if (install_func(& api_impl, NULL /* ext_id */) == 0)
      76  		warning(_("load_ext: library `%s' initialization routine `%s' failed"),
      77  				lib_name, INIT_FUNC);
      78  }
      79  
      80  /* make_builtin --- register name to be called as func with a builtin body */
      81  
      82  awk_bool_t
      83  make_builtin(const char *name_space, const awk_ext_func_t *funcinfo)
      84  {
      85  	NODE *symbol, *f;
      86  	INSTRUCTION *b;
      87  	const char *name = funcinfo->name;
      88  	int count = funcinfo->max_expected_args;
      89  	const char *install_name;
      90  
      91  	if (name == NULL || *name == '\0')
      92  		fatal(_("make_builtin: missing function name"));
      93  
      94  	if (! is_valid_identifier(name))
      95  		return awk_false;
      96  
      97  	assert(name_space != NULL);
      98  	if (name_space[0] == '\0' || strcmp(name_space, awk_namespace) == 0) {
      99  		if (check_special(name) >= 0)
     100  			fatal(_("make_builtin: cannot use gawk built-in `%s' as function name"), name);
     101  
     102  		f = lookup(name);
     103  		install_name = estrdup(name, strlen(name));
     104  	} else {
     105  		if (! is_valid_identifier(name_space))
     106  			return awk_false;
     107  
     108  		if (check_special(name_space) >= 0)
     109  			fatal(_("make_builtin: cannot use gawk built-in `%s' as namespace name"), name_space);
     110  		if (check_special(name) >= 0)
     111  			fatal(_("make_builtin: cannot use gawk built-in `%s' as function name"), name);
     112  
     113  		size_t len = strlen(name_space) + 2 + strlen(name) + 1;
     114  		char *buf;
     115  		emalloc(buf, char *, len, "make_builtin");
     116  		sprintf(buf, "%s::%s", name_space, name);
     117  		install_name = buf;
     118  
     119  		f = lookup(install_name);
     120  	}
     121  
     122  	if (f != NULL) {
     123  		// found it, but it shouldn't be there if we want to install this function
     124  		if (f->type == Node_func) {
     125  			/* user-defined function */
     126  			fatal(_("make_builtin: cannot redefine function `%s'"), name);
     127  		} else if (f->type == Node_ext_func) {
     128  			/* multiple extension() calls etc. */
     129  			if (do_lint)
     130  				lintwarn(_("make_builtin: function `%s' already defined"), name);
     131  			free((void *) install_name);
     132  			return awk_false;
     133  		} else
     134  			/* variable name etc. */
     135  			fatal(_("make_builtin: function name `%s' previously defined"), name);
     136  	}
     137  
     138  	if (count < 0)
     139  		fatal(_("make_builtin: negative argument count for function `%s'"),
     140  				name);
     141  
     142  	b = bcalloc(Op_symbol, 1, 0);
     143  	b->extfunc = funcinfo->function;
     144  	b->c_function = (awk_ext_func_t *) funcinfo;
     145  
     146  	/* NB: extension sub must return something */
     147  
     148  	symbol = install_symbol(install_name, Node_ext_func);
     149  	symbol->code_ptr = b;
     150  	track_ext_func(name);
     151  	return awk_true;
     152  }
     153  
     154  /* get_argument --- get the i'th argument of a dynamically linked function */
     155  
     156  NODE *
     157  get_argument(int i)
     158  {
     159  	NODE *t;
     160  	int arg_count;
     161  	INSTRUCTION *pc;
     162  
     163  	pc = TOP()->code_ptr;		/* Op_ext_builtin instruction */
     164  	arg_count = pc->expr_count;	/* # of arguments supplied */
     165  
     166  	if (i < 0 || i >= arg_count)
     167  		return NULL;
     168  
     169  	t = PEEK(arg_count - i);
     170  	if (t->type == Node_param_list)
     171  		t = GET_PARAM(t->param_cnt);
     172  
     173  	if (t->type == Node_array_ref) {
     174  		if (t->orig_array->type == Node_var) {
     175  			/* already a scalar, can no longer use it as array */
     176  			t->type = Node_var;
     177  			t->var_value = Nnull_string;
     178  			return t;
     179  		}
     180  		return t->orig_array; 	/* Node_var_new or Node_var_array */
     181  	}
     182  	if (t->type == Node_var)	/* See Case Node_var in setup_frame(), eval.c */
     183  		return Nnull_string;
     184  	/* Node_var_new, Node_var_array or Node_val */
     185  	return t;
     186  }
     187  
     188  
     189  /*
     190   * get_actual_argument --- get the i'th scalar or array argument of a
     191   *	dynamically linked function.
     192   */
     193  
     194  NODE *
     195  get_actual_argument(NODE *t, int i, bool want_array)
     196  {
     197  	char *fname;
     198  	INSTRUCTION *pc;
     199  
     200  	pc = TOP()->code_ptr;	/* Op_ext_builtin instruction */
     201  	fname = (pc + 1)->func_name;
     202  
     203  	if (t->type == Node_var_new || t->type == Node_elem_new) {
     204  		if (want_array)
     205  			return force_array(t, false);
     206  		else {
     207  			t->type = Node_var;
     208  			t->var_value = dupnode(Nnull_string);
     209  			return t->var_value;
     210  		}
     211  	}
     212  
     213  	if (want_array) {
     214  		if (t->type != Node_var_array)
     215  			fatal(_("function `%s': argument #%d: attempt to use scalar as an array"),
     216  				fname, i + 1);
     217  	} else {
     218  		if (t->type != Node_val)
     219  			fatal(_("function `%s': argument #%d: attempt to use array as a scalar"),
     220  				fname, i + 1);
     221  	}
     222  	assert(t->type == Node_var_array || t->type == Node_val);
     223  	return t;
     224  }
     225  
     226  #else
     227  
     228  /* load_ext --- dummy version if extensions not available */
     229  
     230  void
     231  load_ext(const char *lib_name)
     232  {
     233  	fatal(_("dynamic loading of libraries is not supported"));
     234  }
     235  #endif
     236  
     237  /* close_extensions --- execute extension cleanup routines */
     238  
     239  void
     240  close_extensions()
     241  {
     242  	SRCFILE *s;
     243  
     244  	if (srcfiles == NULL)
     245  		return;
     246  
     247  	for (s = srcfiles->next; s != srcfiles; s = s->next)
     248  		if (s->stype == SRC_EXTLIB && s->fini_func)
     249                 	        (*s->fini_func)();
     250  }
     251  
     252  /* is_valid_identifier --- return true if name is a valid simple identifier */
     253  
     254  bool
     255  is_valid_identifier(const char *name)
     256  {
     257  	const char *sp = name;
     258  	int c;
     259  
     260  	if (! is_letter(*sp))
     261  		return false;
     262  
     263  	for (sp++; (c = *sp++) != '\0';) {
     264  		if (! is_identchar(c))
     265  			return false;
     266  	}
     267  
     268  	return true;
     269  }