Introduced -devel and -extras subpackages for gawk
[platform/upstream/gawk.git] / 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-2012 the Free Software Foundation, Inc.
11  * 
12  * This file is part of GAWK, the GNU implementation of the
13  * AWK Programming Language.
14  * 
15  * GAWK is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  * 
20  * GAWK is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
28  */
29
30 #include "awk.h"
31
32 #ifdef DYNAMIC
33
34 #include <dlfcn.h>
35
36 /* do_ext --- load an extension */
37
38 NODE *
39 do_ext(int nargs)
40 {
41         NODE *obj;
42         NODE *fun;
43         NODE *tmp = NULL;
44         NODE *(*func)(NODE *, void *);
45         void *dl;
46         int flags = RTLD_LAZY;
47         int fatal_error = FALSE;
48         int *gpl_compat;
49 #if 0
50         static short warned = FALSE;
51 #endif
52
53         if (do_sandbox)
54                 fatal(_("extensions are not allowed in sandbox mode"));
55
56 #if 0
57         /* already done in parser */
58         if (do_lint && ! warned) {
59                 warned = TRUE;
60                 lintwarn(_("`extension' is a gawk extension"));
61         }
62 #endif
63
64         if (do_traditional || do_posix)
65                 error(_("`extension' is a gawk extension"));
66
67         fun = POP_STRING();
68         obj = POP_STRING();
69
70 #ifdef RTLD_GLOBAL
71         flags |= RTLD_GLOBAL;
72 #endif
73         if ((dl = dlopen(obj->stptr, flags)) == NULL) {
74                 /* fatal needs `obj', and we need to deallocate it! */
75                 msg(_("fatal: extension: cannot open `%s' (%s)\n"), obj->stptr,
76                       dlerror());
77                 fatal_error = TRUE;
78                 goto done;
79         }
80
81         /* Per the GNU Coding standards */
82         gpl_compat = (int *) dlsym(dl, "plugin_is_GPL_compatible");
83         if (gpl_compat == NULL) {
84                 msg(_("fatal: extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n"),
85                                 obj->stptr, dlerror());
86                 fatal_error = TRUE;
87                 goto done;
88         }
89
90
91         func = (NODE *(*)(NODE *, void *)) dlsym(dl, fun->stptr);
92         if (func == NULL) {
93                 msg(_("fatal: extension: library `%s': cannot call function `%s' (%s)\n"),
94                                 obj->stptr, fun->stptr, dlerror());
95                 fatal_error = TRUE;
96                 goto done;
97         }
98
99         tmp = (*func)(obj, dl);
100         if (tmp == NULL)
101                 tmp = Nnull_string;
102 done:
103         DEREF(obj);
104         DEREF(fun);
105         if (fatal_error)
106                 gawk_exit(EXIT_FATAL);
107         return tmp; 
108 }
109
110
111 /* make_builtin --- register name to be called as func with a builtin body */
112
113 void
114 make_builtin(const char *name, NODE *(*func)(int), int count)
115 {
116         NODE *p, *symbol, *f;
117         INSTRUCTION *b, *r;
118         const char *sp;
119         char *pname;
120         char **vnames = NULL;
121         char c, buf[200];
122         size_t space_needed;
123         int i;
124
125         sp = name;
126         if (sp == NULL || *sp == '\0')
127                 fatal(_("extension: missing function name"));
128
129         while ((c = *sp++) != '\0') {
130                 if ((sp == &name[1] && c != '_' && ! isalpha((unsigned char) c))
131                                 || (sp > &name[1] && ! is_identchar((unsigned char) c)))
132                         fatal(_("extension: illegal character `%c' in function name `%s'"), c, name);
133         }
134
135         f = lookup(name);
136
137         if (f != NULL) {
138                 if (f->type == Node_func) {
139                         INSTRUCTION *pc = f->code_ptr;
140                         if (pc->opcode != Op_ext_func)  /* user-defined function */
141                                 fatal(_("extension: can't redefine function `%s'"), name);
142                         else {
143                                 /* multiple extension() calls etc. */ 
144                                 if (do_lint)
145                                         lintwarn(_("extension: function `%s' already defined"), name);
146                                 return;
147                         }
148                 } else
149                         /* variable name etc. */ 
150                         fatal(_("extension: function name `%s' previously defined"), name);
151         } else if (check_special(name) >= 0)
152                 fatal(_("extension: can't use gawk built-in `%s' as function name"), name); 
153         /* count parameters, create artificial list of param names */
154
155         if (count < 0)
156                 fatal(_("make_builtin: negative argument count for function `%s'"),
157                                         name);
158
159         if (count > 0) {
160                 sprintf(buf, "p%d", count);
161                 space_needed = strlen(buf) + 1;
162                 emalloc(vnames, char **, count * sizeof(char  *), "make_builtin");
163                 for (i = 0; i < count; i++) {
164                         emalloc(pname, char *, space_needed, "make_builtin");
165                         sprintf(pname, "p%d", i);
166                         vnames[i] = pname;
167                 }
168         }
169
170
171         getnode(p);
172         p->type = Node_param_list;
173         p->flags |= FUNC;
174         /* get our own copy for name */
175         p->param = estrdup(name, strlen(name));
176         p->param_cnt = count;
177
178         /* actual source and line numbers set at runtime for these instructions */
179         b = bcalloc(Op_builtin, 1, __LINE__);
180         b->builtin = func;
181         b->expr_count = count;
182         b->nexti = bcalloc(Op_K_return, 1, __LINE__);
183         r = bcalloc(Op_ext_func, 1, __LINE__);
184         r->source_file = __FILE__;
185         r->nexti = b;
186
187         /* NB: extension sub must return something */
188
189         symbol = mk_symbol(Node_func, p);
190         symbol->parmlist = vnames;
191         symbol->code_ptr = r;
192         r->func_body = symbol;
193         (void) install_symbol(p->param, symbol);
194 }
195
196
197 /* get_curfunc_arg_count --- return number actual parameters */
198
199 size_t
200 get_curfunc_arg_count()
201 {
202         size_t argc;
203         INSTRUCTION *pc;
204         
205         pc = (INSTRUCTION *) frame_ptr->reti;      /* Op_func_call instruction */
206         argc = (pc + 1)->expr_count;        /* # of arguments supplied */
207         return argc;
208 }
209
210
211 /* get_argument --- get the n'th argument of a dynamically linked function */
212
213 NODE *
214 get_argument(int i)
215 {
216         int pcount;
217         NODE *t, *f;
218         int actual_args;
219         INSTRUCTION *pc;
220         
221         f = frame_ptr->func_node;
222         pcount = f->lnode->param_cnt;
223
224         pc = (INSTRUCTION *) frame_ptr->reti;     /* Op_func_call instruction */
225         actual_args = (pc + 1)->expr_count;       /* # of arguments supplied */
226          
227         if (i < 0 || i >= pcount || i >= actual_args)
228                 return NULL;
229
230         t = GET_PARAM(i);
231
232         if (t->type == Node_array_ref)
233                 return t->orig_array;   /* Node_var_new or Node_var_array */
234         if (t->type == Node_var_new || t->type == Node_var_array)
235                 return t;
236         return t->var_value;
237 }
238
239
240 /* get_actual_argument --- get a scalar or array, allowed to be optional */
241
242 NODE *
243 get_actual_argument(int i, int optional, int want_array)
244 {
245         /* optional : if TRUE and i th argument not present return NULL, else fatal. */
246
247         NODE *t, *f;
248         int pcount;
249         char *fname;
250
251         t = get_argument(i);
252
253         f = frame_ptr->func_node;
254         pcount = f->lnode->param_cnt;
255         fname = f->lnode->param;
256
257         if (t == NULL) {
258                 if (i >= pcount)                /* must be fatal */
259                         fatal(_("function `%s' defined to take no more than %d argument(s)"),
260                                         fname, pcount);
261                 if (! optional)
262                         fatal(_("function `%s': missing argument #%d"),
263                                         fname, i + 1);
264                 return NULL;
265         }
266
267         if (t->type == Node_var_new) {
268                 if (want_array)
269                         return get_array(t, FALSE);
270                 else {
271                         t->type = Node_var;
272                         t->var_value = Nnull_string;
273                         return Nnull_string;
274                 }
275         }
276
277         if (want_array) {
278                 if (t->type != Node_var_array)
279                         fatal(_("function `%s': argument #%d: attempt to use scalar as an array"),
280                                 fname, i + 1);
281         } else {
282                 if (t->type != Node_val)
283                         fatal(_("function `%s': argument #%d: attempt to use array as a scalar"),
284                                 fname, i + 1);
285         }
286         return t;
287 }
288
289 #else
290
291 /* do_ext --- dummy version if extensions not available */
292
293 NODE *
294 do_ext(int nargs)
295 {
296         const char *emsg = _("Operation Not Supported");
297
298         unref(ERRNO_node->var_value);
299         ERRNO_node->var_value = make_string(emsg, strlen(emsg));
300         return make_number((AWKNUM) -1);
301 }
302 #endif