1 /*
2 * gretl -- Gnu Regression, Econometrics and Time-series Library
3 * Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "libgretl.h"
21
22 #ifdef WIN32
23 # include <windows.h>
24 #else
25 # include <dlfcn.h>
26 #endif
27
28 /**
29 * SECTION:plugins
30 * @short_description: accessing gretl plugins
31 * @title: Plugins
32 * @include: libgretl.h
33 *
34 * Some of the functionality of libgretl is provided by plugin
35 * modules that are loaded on demand. Here we have functions for
36 * opening and closing plugins, and for obtaining a pointer to
37 * a symbol from a gretl plugin. These functions should work on
38 * both unix-type systems (including Mac OS X) and MS Windows.
39 *
40 * Note that if you wish to make use of gretl plugins in your own
41 * program, you will have to build and install the plugins (of
42 * course) and you may also have to tell libgretl where to
43 * find them. This can be done via the libgretl function
44 * set_gretl_plugin_path(). For example, if the plugins are
45 * in /opt/gretl/lib/gretl-gtk2 then in a C program you could do:
46 *
47 * set_gretl_plugin_path("/opt/gretl/lib/gretl-gtk2");
48 *
49 */
50
51 enum {
52 P_XLS_IMPORT = 1,
53 P_XLSX_IMPORT,
54 P_GNUMERIC_IMPORT,
55 P_ODS_IMPORT,
56 P_JOHANSEN,
57 P_VIF,
58 P_LEVERAGE,
59 P_MP_OLS,
60 P_PCA,
61 P_PROGRESS_BAR,
62 P_RANGE_MEAN,
63 P_STATS_TABLES,
64 P_SYSEST,
65 P_TRAMO_X12A,
66 P_NISTCHECK,
67 P_ARMA,
68 P_ARMA_X12,
69 P_GARCH,
70 P_URCDIST,
71 P_KERNEL,
72 P_FRACTAL,
73 P_POISSON,
74 P_MAILER,
75 P_EVIEWS_IMPORT,
76 P_STATA_IMPORT,
77 P_SPSS_IMPORT,
78 P_SAS_IMPORT,
79 P_JMULTI_IMPORT,
80 P_ZIPFILE,
81 P_DPANEL,
82 P_HECKIT,
83 P_ODBC,
84 P_QUANTREG,
85 P_INTREG,
86 P_ANOVA,
87 P_DURATION,
88 P_INTERPOLATE,
89 P_ISO3166,
90 P_BIPROBIT,
91 P_REPROBIT,
92 P_PANURC,
93 P_JSON_GET,
94 P_XML_GET,
95 P_STATA_EXPORT,
96 P_SVM,
97 P_REGLS,
98 P_GEOPLOT,
99 P_PUREBIN,
100 P_BDSTEST,
101 P_LPSOLVE
102 } plugin_codes;
103
104 struct plugin_info {
105 int pnum; /* index number of plugin */
106 const char *pname; /* name of plugin */
107 void *handle; /* handle obtained via dlopen or similar */
108 };
109
110 struct plugin_function_info {
111 const char *name; /* name of function */
112 int index; /* index of the plugin that supplies it */
113 };
114
115 struct plugin_info plugins[] = {
116 { 0, NULL, NULL },
117 { P_XLS_IMPORT, "excel_import", NULL },
118 { P_XLSX_IMPORT, "xlsx_import", NULL },
119 { P_GNUMERIC_IMPORT, "gnumeric_import", NULL },
120 { P_ODS_IMPORT, "ods_import", NULL },
121 { P_JOHANSEN, "johansen", NULL },
122 { P_VIF, "vif", NULL },
123 { P_LEVERAGE, "leverage", NULL },
124 { P_MP_OLS, "mp_ols", NULL },
125 { P_PCA, "pca", NULL },
126 { P_PROGRESS_BAR, "progress_bar", NULL },
127 { P_RANGE_MEAN, "range-mean", NULL },
128 { P_STATS_TABLES, "stats_tables", NULL },
129 { P_SYSEST, "sysest", NULL },
130 { P_TRAMO_X12A, "tramo-x12a", NULL },
131 { P_NISTCHECK, "nistcheck", NULL },
132 { P_ARMA, "arma", NULL },
133 { P_ARMA_X12, "arma_x12", NULL },
134 { P_GARCH, "garch", NULL },
135 { P_URCDIST, "urcdist", NULL },
136 { P_KERNEL, "kernel", NULL },
137 { P_FRACTAL, "fractals", NULL },
138 { P_POISSON, "poisson", NULL },
139 { P_MAILER, "mailer", NULL },
140 { P_EVIEWS_IMPORT, "eviews_import", NULL },
141 { P_STATA_IMPORT, "stata_import", NULL },
142 { P_SPSS_IMPORT, "spss_import", NULL },
143 { P_SAS_IMPORT, "sas_import", NULL },
144 { P_JMULTI_IMPORT, "jmulti_import", NULL },
145 { P_ZIPFILE, "gretlzip", NULL },
146 { P_DPANEL, "dpanel", NULL },
147 { P_HECKIT, "heckit", NULL },
148 { P_ODBC, "odbc_import", NULL },
149 { P_QUANTREG, "quantreg", NULL },
150 { P_INTREG, "interval", NULL },
151 { P_ANOVA, "anova", NULL },
152 { P_DURATION, "duration", NULL },
153 { P_INTERPOLATE, "interpolate", NULL },
154 { P_ISO3166, "iso3166", NULL },
155 { P_BIPROBIT, "biprobit", NULL },
156 { P_REPROBIT, "reprobit", NULL },
157 { P_PANURC, "panurc", NULL },
158 { P_JSON_GET, "json_get", NULL },
159 { P_XML_GET, "xml_get", NULL },
160 { P_STATA_EXPORT, "stata_export", NULL },
161 { P_SVM, "svm", NULL },
162 { P_REGLS, "regls", NULL },
163 { P_GEOPLOT, "geoplot", NULL },
164 { P_PUREBIN, "purebin", NULL },
165 { P_BDSTEST, "bdstest", NULL },
166 { P_LPSOLVE, "lpsolve", NULL },
167 };
168
169 struct plugin_function_info plugin_functions[] = {
170 /* data importers */
171 { "xls_get_data", P_XLS_IMPORT },
172 { "xlsx_get_data", P_XLSX_IMPORT },
173 { "gnumeric_get_data", P_GNUMERIC_IMPORT },
174 { "ods_get_data", P_ODS_IMPORT },
175 { "wf1_get_data", P_EVIEWS_IMPORT },
176 { "dta_get_data", P_STATA_IMPORT },
177 { "sav_get_data", P_SPSS_IMPORT },
178 { "xport_get_data", P_SAS_IMPORT },
179 { "jmulti_get_data", P_JMULTI_IMPORT },
180
181 /* Johansen cointegration test and VECM */
182 { "johansen_coint_test", P_JOHANSEN },
183 { "johansen_estimate", P_JOHANSEN },
184 { "johansen_boot_round", P_JOHANSEN },
185 { "vecm_test_restriction", P_JOHANSEN },
186 { "trace_pvalue", P_JOHANSEN },
187
188 /* influential observations */
189 { "model_leverage", P_LEVERAGE },
190 { "leverage_data_dialog", P_LEVERAGE },
191
192 /* collinearity diagnostics */
193 { "compute_vifs", P_VIF },
194 { "compute_bkw", P_VIF },
195 { "bkw_matrix", P_VIF },
196
197 /* GMP (multiple precision) */
198 { "mplsq", P_MP_OLS },
199 { "matrix_mp_ols", P_MP_OLS },
200 { "mp_vector_raise_to_power", P_MP_OLS },
201 #ifdef HAVE_MPFR
202 { "mp_vector_ln", P_MP_OLS },
203 #endif
204 { "mp_bw_filter", P_MP_OLS },
205 { "mp_midas_weights", P_MP_OLS },
206 { "mp_midas_gradient", P_MP_OLS },
207
208 /* principal components analysis */
209 { "pca_from_cmatrix", P_PCA },
210
211 /* GUI progress bar */
212 { "show_progress", P_PROGRESS_BAR },
213
214 /* range - mean graph */
215 { "range_mean_graph", P_RANGE_MEAN },
216
217 /* statistical tables */
218 { "dw_lookup", P_STATS_TABLES },
219 { "rank_sum_lookup", P_STATS_TABLES },
220 { "stock_yogo_lookup", P_STATS_TABLES },
221 { "get_IPS_critvals", P_STATS_TABLES },
222 { "IPS_tbar_moments", P_STATS_TABLES },
223 { "IPS_tbar_rho_moments", P_STATS_TABLES },
224 { "qlr_asy_pvalue", P_STATS_TABLES },
225 { "qlr_critval_15_05", P_STATS_TABLES },
226
227 /* SUR, 3SLS, FIML */
228 { "system_estimate", P_SYSEST },
229
230 /* TRAMO/SEATS and X12A */
231 { "write_tx_data", P_TRAMO_X12A },
232 { "exec_tx_script", P_TRAMO_X12A },
233 { "adjust_series", P_TRAMO_X12A },
234 { "linearize_series", P_TRAMO_X12A },
235
236 /* NIST test suite */
237 { "run_nist_tests", P_NISTCHECK },
238
239 /* modeling */
240 { "arma_model", P_ARMA },
241 { "arma_x12_model", P_ARMA_X12 },
242 { "garch_model", P_GARCH },
243 { "count_data_estimate", P_POISSON },
244 { "heckit_estimate", P_HECKIT },
245 { "interval_estimate", P_INTREG },
246 { "tobit_via_intreg", P_INTREG },
247 { "biprobit_estimate", P_BIPROBIT },
248 { "biprobit_adjust_vcv", P_BIPROBIT },
249 { "reprobit_estimate", P_REPROBIT },
250
251 /* Dickey-Fuller test p-values */
252 { "mackinnon_pvalue", P_URCDIST },
253 { "dfgls_pvalue", P_URCDIST },
254
255 /* kernel density estimation */
256 { "kernel_density", P_KERNEL },
257 { "array_kernel_density", P_KERNEL },
258 { "kernel_density_matrix", P_KERNEL },
259 { "multiple_kd_matrix", P_KERNEL },
260
261 /* Hurst exponent estimation */
262 { "hurst_exponent", P_FRACTAL },
263
264 /* Send email */
265 { "email_file", P_MAILER },
266
267 /* zip and unzip */
268 { "gretl_native_make_zipfile", P_ZIPFILE},
269 { "gretl_native_unzip", P_ZIPFILE},
270 { "gretl_native_zip_datafile", P_ZIPFILE},
271
272 /* Dynamic panel data estimation */
273 { "dpd_estimate", P_DPANEL},
274
275 /* ODBC */
276 { "gretl_odbc_check_dsn", P_ODBC},
277 { "gretl_odbc_get_data", P_ODBC},
278
279 /* quantreg */
280 { "rq_driver", P_QUANTREG},
281 { "lad_driver", P_QUANTREG},
282
283 /* analysis of variance */
284 { "gretl_anova", P_ANOVA},
285
286 /* duration models */
287 { "duration_estimate", P_DURATION},
288
289 /* temporal aggregation */
290 { "time_disaggregate", P_INTERPOLATE},
291
292 /* ISO 3166 country codes */
293 { "iso_country", P_ISO3166},
294 { "iso_country_array", P_ISO3166},
295 { "iso_country_series", P_ISO3166},
296
297 /* panel unit roots/cointegration */
298 { "real_levin_lin", P_PANURC},
299
300 /* parsing or writing JSON data */
301 { "json_get_string", P_JSON_GET},
302 { "json_get_bundle", P_JSON_GET},
303 { "json_bundle_get_terminals", P_JSON_GET},
304 { "bundle_to_json", P_JSON_GET},
305
306 /* parsing XML data */
307 { "xml_get", P_XML_GET},
308
309 /* exporting data in dta format */
310 { "stata_export", P_STATA_EXPORT},
311
312 /* libsvm interface */
313 { "gretl_svm_driver", P_SVM},
314
315 /* regularized least squares */
316 { "gretl_regls", P_REGLS},
317 { "regls_xv_mpi", P_REGLS},
318
319 /* shapefile handling */
320 { "map_get_data", P_GEOPLOT},
321 { "shp_get_bundle", P_GEOPLOT},
322 { "geoplot", P_GEOPLOT},
323
324 /* "pure" binary data read/write */
325 { "purebin_read_data", P_PUREBIN},
326 { "purebin_write_data", P_PUREBIN},
327 { "purebin_read_subset", P_PUREBIN},
328 { "purebin_read_varnames", P_PUREBIN},
329
330 /* BDS nonlinearity test */
331 { "bdstest", P_BDSTEST},
332
333 /* interface to lpsolve library */
334 { "gretl_lpsolve", P_LPSOLVE},
335
336 /* sentinel */
337 { NULL, 0 }
338 };
339
gretl_plugin_hash_init(void)340 static GHashTable *gretl_plugin_hash_init (void)
341 {
342 GHashTable *ht;
343 int i;
344
345 ht = g_hash_table_new(g_str_hash, g_str_equal);
346
347 /* Record the plugin index of each plugin function
348 in a hash table under the key of the function
349 name, permitting quick look-up.
350 */
351 for (i=0; plugin_functions[i].name != NULL; i++) {
352 g_hash_table_insert(ht, (gpointer) plugin_functions[i].name,
353 GINT_TO_POINTER(plugin_functions[i].index));
354 }
355
356 return ht;
357 }
358
plugin_index_lookup(const char * name)359 static int plugin_index_lookup (const char *name)
360 {
361 static GHashTable *pht;
362 gpointer ptr;
363
364 if (name == NULL) {
365 /* cleanup signal */
366 if (pht != NULL) {
367 g_hash_table_destroy(pht);
368 pht = NULL;
369 }
370 return 0;
371 }
372
373 if (pht == NULL) {
374 /* construct hash table if not already done */
375 pht = gretl_plugin_hash_init();
376 }
377
378 ptr = g_hash_table_lookup(pht, name);
379
380 return ptr == NULL ? 0 : GPOINTER_TO_INT(ptr);
381 }
382
383 /**
384 * gretl_dlopen:
385 * @path: full path to the shared object to be opened.
386 * @now: on *nix, if non-zero we call dlopen with the flag
387 * RTLD_NOW, else we use RTLD_LAZY.
388 *
389 * Cross-platform wrapper for opening a shared code object
390 * on MS Windows or unix-type systems (including OS X).
391 *
392 * Returns: handle to the shared object.
393 */
394
gretl_dlopen(const char * path,int now)395 void *gretl_dlopen (const char *path, int now)
396 {
397 void *handle = NULL;
398
399 #ifdef WIN32
400 if (strstr(path, "R.dll")) {
401 handle = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
402 } else {
403 handle = LoadLibrary(path);
404 }
405 #else
406 handle = dlopen(path, (now)? RTLD_NOW : RTLD_LAZY);
407 #endif
408
409 if (handle == NULL) {
410 gretl_errmsg_sprintf(_("Failed to load plugin: %s"), path);
411 #if !defined(WIN32)
412 fprintf(stderr, "%s\n", dlerror());
413 #endif
414 }
415
416 return handle;
417 }
418
419 /**
420 * gretl_dlsym:
421 * @handle: handle to shared object; see gretl_dlopen().
422 * @name: name of symbol to look up.
423 *
424 * Cross-platform wrapper for obtaining a pointer to
425 * a named symbol in a shared object represented by
426 * @handle.
427 *
428 * Returns: pointer corresponding to @name, or NULL.
429 */
430
gretl_dlsym(void * handle,const char * name)431 void *gretl_dlsym (void *handle, const char *name)
432 {
433 #ifdef WIN32
434 return GetProcAddress(handle, name);
435 #else
436 return dlsym(handle, name);
437 #endif
438 }
439
440 #if defined(WIN32) || defined(__CYGWIN__)
441 # define PLUGIN_EXT ".dll"
442 #else
443 # define PLUGIN_EXT ".so"
444 #endif
445
get_plugin_handle_by_index(int i)446 static void *get_plugin_handle_by_index (int i)
447 {
448 void *handle = plugins[i].handle;
449
450 if (handle == NULL) {
451 /* not opened yet */
452 char pluginpath[MAXLEN];
453
454 strcpy(pluginpath, gretl_plugin_path());
455 strcat(pluginpath, plugins[i].pname);
456 strcat(pluginpath, PLUGIN_EXT);
457
458 handle = gretl_dlopen(pluginpath, 0);
459 /* store the pointer we got */
460 plugins[i].handle = handle;
461 }
462
463 return handle;
464 }
465
get_function_address(void * handle,const char * name)466 static void *get_function_address (void *handle,
467 const char *name)
468 {
469 void *funp;
470
471 #ifdef WIN32
472 funp = GetProcAddress(handle, name);
473 #else
474 funp = dlsym(handle, name);
475 if (funp == NULL) {
476 gchar *munged = g_strdup_printf("_%s", name);
477
478 funp = dlsym(handle, munged);
479 if (funp == NULL) {
480 fprintf(stderr, "%s\n", dlerror());
481 }
482 g_free(munged);
483 }
484 #endif
485
486 return funp;
487 }
488
plugins_cleanup(void)489 void plugins_cleanup (void)
490 {
491 int i, n = sizeof(plugins) / sizeof(plugins[0]);
492
493 /* note: plugins[0] is a dummy entry */
494
495 for (i=1; i<n; i++) {
496 if (plugins[i].handle != NULL) {
497 close_plugin(plugins[i].handle);
498 plugins[i].handle = NULL;
499 }
500 }
501
502 /* tear down the plugin look-up hash table */
503 plugin_index_lookup(NULL);
504 }
505
506 /**
507 * get_plugin_function:
508 * @funcname: name of function to access.
509 *
510 * Looks up @funcname in gretl's internal plugin table and
511 * attempts to open the plugin object file that offers the
512 * given function.
513 *
514 * Returns: function pointer, or NULL on failure.
515 */
516
get_plugin_function(const char * funcname)517 void *get_plugin_function (const char *funcname)
518 {
519 int i = plugin_index_lookup(funcname);
520 void *funp = NULL;
521
522 #if !HAVE_GMP
523 if (i == P_MP_OLS) {
524 gretl_errmsg_set("GMP is not supported in this build");
525 return NULL;
526 }
527 #endif
528
529 if (i > 0) {
530 void *handle = get_plugin_handle_by_index(i);
531
532 if (handle != NULL) {
533 funp = get_function_address(handle, funcname);
534 } else {
535 fprintf(stderr, "%s: get_function_address failed\n",
536 funcname);
537 }
538 } else {
539 fprintf(stderr, "%s: plugin_index_lookup failed\n",
540 funcname);
541 }
542
543 if (funp == NULL) {
544 gretl_errmsg_set(_("Couldn't load plugin function"));
545 }
546
547 return funp;
548 }
549
get_plugin_handle_by_name(const char * name)550 static void *get_plugin_handle_by_name (const char *name)
551 {
552 char pluginpath[MAXLEN];
553
554 strcpy(pluginpath, gretl_plugin_path());
555 strcat(pluginpath, name);
556 strcat(pluginpath, PLUGIN_EXT);
557
558 return gretl_dlopen(pluginpath, 0);
559 }
560
get_packaged_C_function(const char * pkgname,const char * funcname,void ** handle)561 void *get_packaged_C_function (const char *pkgname,
562 const char *funcname,
563 void **handle)
564 {
565 void *funp;
566
567 *handle = get_plugin_handle_by_name(pkgname);
568 if (*handle == NULL) {
569 return NULL;
570 }
571
572 funp = get_function_address(*handle, funcname);
573
574 if (funp == NULL) {
575 gretl_errmsg_set(_("Couldn't load plugin function"));
576 close_plugin(*handle);
577 *handle = NULL;
578 }
579
580 return funp;
581 }
582
583 /* For use with valgrind: if you want to trace memory
584 leaks into plugin code you have to keep the plugins
585 open at program termination. So you can define this
586 as non-zero temporarily.
587 */
588 #define KEEP_PLUGINS_OPEN 0
589
590 /**
591 * close_plugin:
592 * @handle: pointer obtained via the handle argument to
593 * get_plugin_function().
594 *
595 * Closes a shared plugin object.
596 */
597
close_plugin(void * handle)598 void close_plugin (void *handle)
599 {
600 #if KEEP_PLUGINS_OPEN
601 return;
602 #endif
603 if (handle != NULL) {
604 #ifdef WIN32
605 FreeLibrary(handle);
606 #else
607 dlclose(handle);
608 #endif
609 }
610 }
611