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 "gretl.h"
21 #include "version.h"
22 #include "dlgutils.h"
23 #include "selector.h"
24 #include "gretl_func.h"
25 #include "monte_carlo.h"
26 #include "uservar.h"
27 #include "cmd_private.h"
28 #include "gretl_www.h"
29 #include "gretl_xml.h"
30 #include "gretl_typemap.h"
31 #include "matrix_extra.h"
32 #include "gretl_zip.h"
33 #include "addons_utils.h"
34 #include "database.h"
35 #include "guiprint.h"
36 #include "ssheet.h"
37 #include "datafiles.h"
38 #include "toolbar.h"
39 #include "obsbutton.h"
40 #include "cmdstack.h"
41 #include "winstack.h"
42 #include "treeutils.h"
43 #include "gfn_arglists.h"
44 #include "gpt_control.h"
45 #include "fnsave.h"
46 #include "fncall.h"
47
48 #include <errno.h>
49
50 #define FCDEBUG 0
51 #define PKG_DEBUG 0
52 #define MPKG_DEBUG 0
53
54 enum {
55 SHOW_GUI_MAIN = 1 << 0,
56 MODEL_CALL = 1 << 1,
57 DATA_ACCESS = 1 << 2
58 };
59
60 typedef struct call_info_ call_info;
61
62 struct call_info_ {
63 GtkWidget *dlg; /* main dialog */
64 GtkWidget *top_hbox; /* upper hbox in dialog */
65 windata_t *vwin; /* gretl caller window */
66 GList *vsels; /* series argument selectors */
67 GList *lsels; /* list argument selectors */
68 GList *msels; /* matrix arg selectors */
69 GList *ssels; /* scalar arg selectors */
70 GList *bsels; /* bundle arg selectors */
71 GList *asels; /* array arg selectors */
72 fnpkg *pkg; /* the active function package */
73 gchar *pkgname; /* and its name */
74 gchar *pkgver; /* plus its version */
75 int *publist; /* list of public interfaces */
76 int iface; /* selected interface */
77 int flags; /* misc. info on package */
78 const ufunc *func; /* the function we're calling */
79 DataReq dreq; /* the function's data requirement */
80 int modelreq; /* the function's model (command) requirement */
81 int minver; /* minimum gretl version for pkg */
82 int n_params; /* its number of parameters */
83 char rettype; /* its return type */
84 gchar **args; /* its arguments */
85 gchar *ret; /* return assignment name */
86 gchar *label; /* the function's label */
87 };
88
89 #define scalar_arg(t) (t == GRETL_TYPE_DOUBLE || t == GRETL_TYPE_SCALAR_REF)
90 #define series_arg(t) (t == GRETL_TYPE_SERIES || t == GRETL_TYPE_SERIES_REF)
91 #define matrix_arg(t) (t == GRETL_TYPE_MATRIX || t == GRETL_TYPE_MATRIX_REF)
92 #define bundle_arg(t) (t == GRETL_TYPE_BUNDLE || t == GRETL_TYPE_BUNDLE_REF)
93 #define array_arg(t) (t == GRETL_TYPE_ARRAY || t == GRETL_TYPE_ARRAY_REF)
94
95 #define AUTOLIST "LTmp___"
96 #define DUMLIST "LRetTmp___"
97 #define SELNAME "selected series"
98
99 static GtkWidget *open_fncall_dlg;
100 static gboolean close_on_OK = TRUE;
101 static gboolean allow_full_data = TRUE;
102
103 static void fncall_exec_callback (GtkWidget *w, call_info *cinfo);
104 static void maybe_record_include (const char *pkgname, int model_id);
105 static void set_genr_model_from_vwin (windata_t *vwin);
106 static void maybe_open_sample_script (call_info *cinfo,
107 windata_t *vwin,
108 const char *path);
109
glib_str_array_new(int n)110 static gchar **glib_str_array_new (int n)
111 {
112 gchar **S = g_malloc0(n * sizeof *S);
113
114 return S;
115 }
116
glib_str_array_free(gchar ** S,int n)117 static void glib_str_array_free (gchar **S, int n)
118 {
119 if (S != NULL) {
120 int i;
121
122 for (i=0; i<n; i++) {
123 g_free(S[i]);
124 }
125 g_free(S);
126 }
127 }
128
caller_is_model_window(windata_t * vwin)129 static int caller_is_model_window (windata_t *vwin)
130 {
131 if (vwin != NULL &&
132 (vwin->role == VIEW_MODEL ||
133 vwin->role == VAR ||
134 vwin->role == VECM ||
135 vwin->role == SYSTEM) &&
136 vwin->data != NULL) {
137 return 1;
138 }
139
140 return 0;
141 }
142
cinfo_new(fnpkg * pkg,windata_t * vwin)143 static call_info *cinfo_new (fnpkg *pkg, windata_t *vwin)
144 {
145 call_info *cinfo = mymalloc(sizeof *cinfo);
146
147 if (cinfo == NULL) {
148 return NULL;
149 }
150
151 cinfo->pkg = pkg;
152 cinfo->pkgname = NULL;
153 cinfo->pkgver = NULL;
154
155 cinfo->vwin = vwin;
156 cinfo->dlg = NULL;
157 cinfo->top_hbox = NULL;
158
159 cinfo->publist = NULL;
160 cinfo->iface = -1;
161 cinfo->flags = 0;
162
163 if (caller_is_model_window(vwin)) {
164 cinfo->flags |= MODEL_CALL;
165 }
166
167 cinfo->vsels = NULL;
168 cinfo->lsels = NULL;
169 cinfo->msels = NULL;
170 cinfo->bsels = NULL;
171 cinfo->asels = NULL;
172 cinfo->ssels = NULL;
173
174 cinfo->func = NULL;
175 cinfo->n_params = 0;
176
177 cinfo->rettype = GRETL_TYPE_NONE;
178
179 cinfo->args = NULL;
180 cinfo->ret = NULL;
181
182 cinfo->dreq = FN_NEEDS_DATA;
183 cinfo->modelreq = 0;
184 cinfo->label = NULL;
185
186 return cinfo;
187 }
188
189 static int *mylist; /* custom list constructed by gfn */
190
lmaker_run(ufunc * func,call_info * cinfo)191 static int lmaker_run (ufunc *func, call_info *cinfo)
192 {
193 fncall *fcall = NULL;
194 int *biglist = NULL;
195 int *list = NULL;
196 PRN *prn;
197 int err = 0;
198
199 free(mylist);
200 mylist = NULL;
201
202 fcall = fncall_new(func, 0);
203 if (fn_n_params(func) == 1) {
204 /* pass full dataset list as argument */
205 biglist = full_var_list(dataset, NULL);
206 if (biglist != NULL) {
207 push_anon_function_arg(fcall, GRETL_TYPE_LIST, biglist);
208 }
209 }
210
211 prn = gretl_print_new(GRETL_PRINT_STDERR, &err);
212 if (cinfo->flags & MODEL_CALL) {
213 set_genr_model_from_vwin(cinfo->vwin);
214 }
215 err = gretl_function_exec(fcall, GRETL_TYPE_LIST, dataset,
216 &list, NULL, prn);
217 if (cinfo->flags & MODEL_CALL) {
218 unset_genr_model();
219 }
220 gretl_print_destroy(prn);
221
222 if (err) {
223 gui_errmsg(err);
224 }
225
226 if (!err && list == NULL) {
227 err = 1;
228 }
229
230 if (!err) {
231 mylist = list;
232 list = NULL;
233 }
234
235 free(list);
236 free(biglist);
237
238 return err;
239 }
240
cinfo_args_init(call_info * cinfo)241 static int cinfo_args_init (call_info *cinfo)
242 {
243 int err = 0;
244
245 cinfo->args = NULL;
246 cinfo->ret = NULL;
247
248 if (cinfo->n_params > 0) {
249 cinfo->args = glib_str_array_new(cinfo->n_params);
250 if (cinfo->args == NULL) {
251 err = E_ALLOC;
252 }
253 }
254
255 return err;
256 }
257
cinfo_free(call_info * cinfo)258 static void cinfo_free (call_info *cinfo)
259 {
260 if (cinfo->n_params > 0) {
261 glib_str_array_free(cinfo->args, cinfo->n_params);
262 }
263 if (cinfo->ret != NULL) {
264 g_free(cinfo->ret);
265 }
266 if (cinfo->vsels != NULL) {
267 g_list_free(cinfo->vsels);
268 }
269 if (cinfo->lsels != NULL) {
270 g_list_free(cinfo->lsels);
271 }
272 if (cinfo->msels != NULL) {
273 g_list_free(cinfo->msels);
274 }
275 if (cinfo->bsels != NULL) {
276 g_list_free(cinfo->bsels);
277 }
278 if (cinfo->asels != NULL) {
279 g_list_free(cinfo->asels);
280 }
281 if (cinfo->ssels != NULL) {
282 g_list_free(cinfo->ssels);
283 }
284
285 g_free(cinfo->pkgname);
286 g_free(cinfo->pkgver);
287
288 g_free(cinfo->label);
289 free(cinfo->publist);
290 free(cinfo);
291 }
292
check_args(call_info * cinfo)293 static int check_args (call_info *cinfo)
294 {
295 int i;
296
297 if (cinfo->args != NULL) {
298 for (i=0; i<cinfo->n_params; i++) {
299 if (cinfo->args[i] == NULL) {
300 if (fn_param_optional(cinfo->func, i)) {
301 cinfo->args[i] = g_strdup("null");
302 } else {
303 errbox_printf(_("Argument %d (%s) is missing"), i + 1,
304 fn_param_name(cinfo->func, i));
305 return 1;
306 }
307 }
308 }
309 }
310
311 return 0;
312 }
313
fncall_dialog_destruction(GtkWidget * w,call_info * cinfo)314 static void fncall_dialog_destruction (GtkWidget *w, call_info *cinfo)
315 {
316 /* turn off out-of-sample data access */
317 allow_full_data_access(0);
318 cinfo_free(cinfo);
319 open_fncall_dlg = NULL;
320 }
321
fncall_close(GtkWidget * w,call_info * cinfo)322 static void fncall_close (GtkWidget *w, call_info *cinfo)
323 {
324 gtk_widget_destroy(cinfo->dlg);
325 }
326
label_hbox(call_info * cinfo,GtkWidget * w)327 static GtkWidget *label_hbox (call_info *cinfo, GtkWidget *w)
328 {
329 GtkWidget *hbox, *lbl;
330 gchar *buf = NULL;
331
332 hbox = gtk_hbox_new(FALSE, 5);
333 gtk_box_pack_start(GTK_BOX(w), hbox, FALSE, FALSE, 5);
334
335 if (cinfo->label != NULL) {
336 buf = g_markup_printf_escaped("<span weight=\"bold\">%s</span>",
337 _(cinfo->label));
338 } else {
339 const char *funcname;
340
341 funcname = user_function_name_by_index(cinfo->iface);
342 buf = g_markup_printf_escaped("<span weight=\"bold\">%s</span>",
343 funcname);
344 }
345
346 lbl = gtk_label_new(NULL);
347 gtk_label_set_markup(GTK_LABEL(lbl), buf);
348 g_free(buf);
349
350 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 5);
351 gtk_widget_show(lbl);
352
353 return hbox;
354 }
355
update_double_arg(GtkWidget * w,call_info * cinfo)356 static gboolean update_double_arg (GtkWidget *w, call_info *cinfo)
357 {
358 double val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w));
359 int i = widget_get_int(w, "argnum");
360
361 g_free(cinfo->args[i]);
362 cinfo->args[i] = g_strdup_printf("%g", val);
363
364 return FALSE;
365 }
366
update_int_arg(GtkWidget * w,call_info * cinfo)367 static gboolean update_int_arg (GtkWidget *w, call_info *cinfo)
368 {
369 int val = (int) gtk_spin_button_get_value(GTK_SPIN_BUTTON(w));
370 int i = widget_get_int(w, "argnum");
371
372 g_free(cinfo->args[i]);
373 cinfo->args[i] = g_strdup_printf("%d", val);
374
375 return FALSE;
376 }
377
update_bool_arg(GtkWidget * w,call_info * cinfo)378 static gboolean update_bool_arg (GtkWidget *w, call_info *cinfo)
379 {
380 int i = widget_get_int(w, "argnum");
381
382 g_free(cinfo->args[i]);
383 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
384 cinfo->args[i] = g_strdup("1");
385 } else {
386 cinfo->args[i] = g_strdup("0");
387 }
388
389 return FALSE;
390 }
391
combo_box_get_trimmed_text(GtkComboBox * combo)392 static gchar *combo_box_get_trimmed_text (GtkComboBox *combo)
393 {
394 gchar *s = combo_box_get_active_text(combo);
395 gchar *ret = NULL;
396
397 if (s != NULL && *s != '\0') {
398 while (isspace(*s)) s++;
399 if (*s != '\0') {
400 int i, len = strlen(s);
401
402 for (i=len-1; i>0; i--) {
403 if (!isspace(s[i])) break;
404 len--;
405 }
406
407 if (len > 0) {
408 ret = g_strndup(s, len);
409 }
410 }
411 }
412
413 g_free(s);
414
415 return ret;
416 }
417
update_arg(GtkComboBox * combo,call_info * cinfo)418 static gboolean update_arg (GtkComboBox *combo,
419 call_info *cinfo)
420 {
421 int i = widget_get_int(combo, "argnum");
422 char *s;
423
424 g_free(cinfo->args[i]);
425 s = cinfo->args[i] = combo_box_get_trimmed_text(combo);
426
427 if (s != NULL && fn_param_type(cinfo->func, i) == GRETL_TYPE_DOUBLE) {
428 if (isdigit(*s) || *s == '-' || *s == '+' || *s == ',') {
429 gretl_charsub(s, ',', '.');
430 }
431 }
432
433 return FALSE;
434 }
435
update_return(GtkComboBox * combo,call_info * cinfo)436 static gboolean update_return (GtkComboBox *combo,
437 call_info *cinfo)
438 {
439 g_free(cinfo->ret);
440 cinfo->ret = combo_box_get_trimmed_text(combo);
441
442 return FALSE;
443 }
444
445 /* simple heuristic for whether or not a series probably
446 represents a stochastic variable
447 */
448
probably_stochastic(int v)449 static int probably_stochastic (int v)
450 {
451 int ret = 1;
452
453 if (sample_size(dataset) >= 3) {
454 /* rule out vars that seem to be integer-valued with
455 a constant increment */
456 int t = dataset->t1;
457 double d1 = dataset->Z[v][t+1] - dataset->Z[v][t];
458 double d2 = dataset->Z[v][t+2] - dataset->Z[v][t+1];
459
460 if (d1 == floor(d1) && d2 == d1) {
461 ret = 0;
462 }
463 }
464
465 return ret;
466 }
467
add_names_for_type(GList * list,GretlType type)468 static GList *add_names_for_type (GList *list, GretlType type)
469 {
470 GList *tlist = user_var_names_for_type(type);
471 GList *tail = tlist;
472
473 while (tail != NULL) {
474 list = g_list_append(list, tail->data);
475 tail = tail->next;
476 }
477
478 if (type == GRETL_TYPE_LIST && mdata_selection_count() > 1) {
479 list = g_list_append(list, SELNAME);
480 }
481
482 g_list_free(tlist);
483
484 return list;
485 }
486
add_series_names(GList * list)487 static GList *add_series_names (GList *list)
488 {
489 int i;
490
491 for (i=1; i<dataset->v; i++) {
492 if (!series_is_hidden(dataset, i)) {
493 list = g_list_append(list, (gpointer) dataset->varname[i]);
494 }
495 }
496
497 list = g_list_append(list, (gpointer) dataset->varname[0]);
498
499 return list;
500 }
501
get_selection_list(int type)502 static GList *get_selection_list (int type)
503 {
504 GList *list = NULL;
505
506 if (series_arg(type)) {
507 list = add_series_names(list);
508 } else if (scalar_arg(type)) {
509 list = add_names_for_type(list, GRETL_TYPE_DOUBLE);
510 } else if (type == GRETL_TYPE_LIST) {
511 list = add_names_for_type(list, GRETL_TYPE_LIST);
512 } else if (matrix_arg(type)) {
513 list = add_names_for_type(list, GRETL_TYPE_MATRIX);
514 } else if (bundle_arg(type)) {
515 list = add_names_for_type(list, GRETL_TYPE_BUNDLE);
516 } else if (array_arg(type)) {
517 list = add_names_for_type(list, GRETL_TYPE_ARRAY);
518 }
519
520 return list;
521 }
522
make_help_viewer(const char * fnname,const char * pdfname,PRN * prn)523 static windata_t *make_help_viewer (const char *fnname,
524 const char *pdfname,
525 PRN *prn)
526 {
527 windata_t *vwin;
528 gchar *title;
529 char *buf;
530
531 if (pdfname != NULL) {
532 /* append a link to the PDF file */
533 gchar *localpdf = g_strdup(pdfname);
534 gchar *p = strrchr(localpdf, '.');
535
536 *p = '\0';
537 strcat(p, ".pdf");
538 pprintf(prn, "<@itl=\"Documentation\">: <@adb=\"%s\">\n", localpdf);
539 g_free(localpdf);
540 }
541
542 buf = gretl_print_steal_buffer(prn);
543 title = g_strdup_printf(_("help on %s"), fnname);
544 vwin = view_formatted_text_buffer(title, buf, 76, 350, VIEW_PKG_INFO);
545 g_free(title);
546 free(buf);
547
548 return vwin;
549 }
550
fncall_help(GtkWidget * w,call_info * cinfo)551 static void fncall_help (GtkWidget *w, call_info *cinfo)
552 {
553 char *pdfname = NULL;
554 int show_ghlp = 0;
555 int have_pdf = 0;
556
557 if ((cinfo->flags & SHOW_GUI_MAIN) &&
558 function_package_has_gui_help(cinfo->pkg)) {
559 show_ghlp = 1;
560 }
561
562 have_pdf = function_package_has_PDF_doc(cinfo->pkg, &pdfname);
563
564 if (have_pdf && !show_ghlp) {
565 /* simple: just show PDF doc */
566 FILE *fp = gretl_fopen(pdfname, "r");
567
568 if (fp != NULL) {
569 fclose(fp);
570 gretl_show_pdf(pdfname, NULL);
571 } else {
572 gui_errmsg(E_FOPEN);
573 }
574 } else {
575 /* show help text, either "plain" or GUI */
576 const char *fnname;
577 PRN *prn = NULL;
578 gretlopt opt = OPT_M;
579 int err;
580
581 if (bufopen(&prn)) {
582 return;
583 }
584
585 if (show_ghlp) {
586 opt |= OPT_G;
587 }
588
589 fnname = user_function_name_by_index(cinfo->iface);
590 err = user_function_help(fnname, opt, prn);
591
592 if (err) {
593 gretl_print_destroy(prn);
594 errbox("Couldn't find any help");
595 } else {
596 make_help_viewer(fnname, pdfname, prn);
597 gretl_print_destroy(prn);
598 }
599 }
600
601 free(pdfname);
602 }
603
combo_list_index(const gchar * s,GList * list)604 static int combo_list_index (const gchar *s, GList *list)
605 {
606 GList *tmp = list;
607 int i;
608
609 for (i=0; tmp != NULL; i++) {
610 if (!strcmp(s, (gchar *) tmp->data)) {
611 return i;
612 }
613 tmp = tmp->next;
614 }
615
616 return -1;
617 }
618
619 /* Update the combo argument selector(s) for series, matrices
620 lists or scalars after defining a new variable of one of
621 these types.
622 */
623
update_combo_selectors(call_info * cinfo,GtkWidget * refsel,int ptype)624 static void update_combo_selectors (call_info *cinfo,
625 GtkWidget *refsel,
626 int ptype)
627 {
628 GList *sellist, *newlist;
629 int llen;
630
631 /* get the list of relevant selectors and the
632 list of relevant variables to put into the
633 selectors
634 */
635
636 if (ptype == GRETL_TYPE_MATRIX) {
637 sellist = g_list_first(cinfo->msels);
638 } else if (ptype == GRETL_TYPE_BUNDLE) {
639 sellist = g_list_first(cinfo->bsels);
640 } else if (ptype == GRETL_TYPE_ARRAY) {
641 sellist = g_list_first(cinfo->asels);
642 } else if (ptype == GRETL_TYPE_LIST) {
643 sellist = g_list_first(cinfo->lsels);
644 } else if (ptype == GRETL_TYPE_DOUBLE) {
645 sellist = g_list_first(cinfo->ssels);
646 } else {
647 sellist = g_list_first(cinfo->vsels);
648 }
649
650 newlist = get_selection_list(ptype);
651 llen = g_list_length(newlist);
652
653 while (sellist != NULL) {
654 /* iterate over the affected selectors */
655 GtkComboBox *sel = GTK_COMBO_BOX(sellist->data);
656 int target = GTK_WIDGET(sel) == refsel;
657 int null_OK, selpos;
658 gchar *saved = NULL;
659
660 /* target == 1 means that we're looking at the
661 selector whose button was clicked to add a
662 variable: for this selector the newly added
663 variable should be marked as selected;
664 otherwise we modify the list of choices but
665 preserve the previous selection.
666 */
667
668 if (!target) {
669 /* make a record of the old selected item */
670 saved = combo_box_get_active_text(sel);
671 }
672
673 depopulate_combo_box(sel);
674 set_combo_box_strings_from_list(GTK_WIDGET(sel), newlist);
675 null_OK = widget_get_int(sel, "null_OK");
676 if (null_OK) {
677 combo_box_append_text(sel, "null");
678 }
679
680 if (target) {
681 /* select the newly added var, which will be at the
682 end, or thereabouts */
683 selpos = llen - 1;
684 if (series_arg(ptype)) {
685 selpos--; /* the const is always in last place */
686 }
687 gtk_combo_box_set_active(sel, selpos);
688 } else if (saved != NULL) {
689 /* reinstate the previous selection */
690 selpos = combo_list_index(saved, newlist);
691 if (selpos < 0) {
692 if (*saved == '\0') {
693 combo_box_prepend_text(sel, "");
694 selpos = 0;
695 } else if (!strcmp(saved, "null")) {
696 selpos = llen;
697 }
698 }
699 gtk_combo_box_set_active(sel, selpos);
700 g_free(saved);
701 } else {
702 /* reinstate empty selection */
703 gtk_combo_box_set_active(sel, -1);
704 }
705
706 sellist = sellist->next;
707 }
708
709 g_list_free(newlist);
710 }
711
do_make_list(selector * sr)712 static int do_make_list (selector *sr)
713 {
714 const char *buf = selector_list(sr);
715 const char *lname = selector_entry_text(sr);
716 gpointer data = selector_get_data(sr);
717 call_info *cinfo = NULL;
718 GtkWidget *aux = NULL;
719 const char *msg = NULL;
720 PRN *prn = NULL;
721 int *list = NULL;
722 int empty = 0;
723 int nl, err = 0;
724
725 if (lname == NULL || *lname == '\0') {
726 errbox(_("No name was given for the list"));
727 return 1;
728 }
729
730 err = gui_validate_varname(lname, GRETL_TYPE_LIST,
731 selector_get_window(sr));
732 if (err) {
733 return err;
734 }
735
736 if (data != NULL) {
737 /* called from elsewhere in fncall.c */
738 GtkWidget *entry = GTK_WIDGET(data);
739
740 cinfo = g_object_get_data(G_OBJECT(entry), "cinfo");
741 aux = g_object_get_data(G_OBJECT(entry), "sel");
742 }
743
744 /* record initial status */
745 nl = n_user_lists();
746
747 if (buf == NULL || *buf == '\0') {
748 int resp;
749
750 resp = yes_no_dialog("gretl", _("Really create an empty list?"),
751 selector_get_window(sr));
752 if (resp == GRETL_YES) {
753 list = gretl_null_list();
754 if (list == NULL) {
755 err = E_ALLOC;
756 } else {
757 empty = 1;
758 }
759 } else {
760 /* canceled */
761 return 0;
762 }
763 } else {
764 list = command_list_from_string(buf, &err);
765 }
766
767 if (err) {
768 gui_errmsg(err);
769 return err;
770 }
771
772 if (cinfo != NULL) {
773 /* don't bother with "Added list..." message */
774 err = remember_list(list, lname, NULL);
775 if (err) {
776 gui_errmsg(err);
777 }
778 } else {
779 if (bufopen(&prn)) {
780 free(list);
781 return 1;
782 }
783 err = remember_list(list, lname, prn);
784 msg = gretl_print_get_buffer(prn);
785 if (err) {
786 errbox(msg);
787 }
788 }
789
790 if (!err) {
791 lib_command_sprintf("list %s =%s", lname, empty ? " null" : buf);
792 record_command_verbatim();
793 gtk_widget_hide(selector_get_window(sr));
794 if (cinfo != NULL) {
795 if (n_user_lists() > nl) {
796 update_combo_selectors(cinfo, aux, GRETL_TYPE_LIST);
797 }
798 } else {
799 infobox(msg);
800 }
801 }
802
803 free(list);
804
805 if (prn != NULL) {
806 gretl_print_destroy(prn);
807 }
808
809 return err;
810 }
811
launch_list_maker(GtkWidget * button,GtkWidget * entry)812 static void launch_list_maker (GtkWidget *button, GtkWidget *entry)
813 {
814 call_info *cinfo;
815
816 cinfo = g_object_get_data(G_OBJECT(button), "cinfo");
817 g_object_set_data(G_OBJECT(cinfo->dlg), "button", button);
818 simple_selection_with_data(DEFINE_LIST, _("Define list"),
819 do_make_list, cinfo->dlg,
820 entry);
821 }
822
gui_define_list(void)823 void gui_define_list (void)
824 {
825 simple_selection_with_data(DEFINE_LIST, _("Define list"),
826 do_make_list, NULL, NULL);
827 }
828
launch_matrix_maker(GtkWidget * button,call_info * cinfo)829 static void launch_matrix_maker (GtkWidget *button, call_info *cinfo)
830 {
831 int n = n_user_matrices();
832
833 if (!strcmp(cinfo->pkgname, "SVAR")) {
834 widget_set_int(cinfo->dlg, "matrix-no-series", 1);
835 }
836
837 g_object_set_data(G_OBJECT(cinfo->dlg), "button", button);
838 fncall_add_matrix(cinfo->dlg);
839
840 if (n_user_matrices() > n) {
841 GtkWidget *sel = g_object_get_data(G_OBJECT(button), "combo");
842
843 update_combo_selectors(cinfo, sel, GRETL_TYPE_MATRIX);
844 }
845
846 gtk_window_present(GTK_WINDOW(cinfo->dlg));
847 }
848
849 /* callback after invoking "genr" via the "+" button
850 beside a combo argument selector */
851
fncall_register_genr(int addv,gpointer p)852 void fncall_register_genr (int addv, gpointer p)
853 {
854 GtkWidget *combo = p;
855 GtkWidget *entry = gtk_bin_get_child(GTK_BIN(combo));
856 call_info *cinfo = g_object_get_data(G_OBJECT(entry), "cinfo");
857 int ptype = widget_get_int(combo, "ptype");
858
859 if (addv > 0) {
860 update_combo_selectors(cinfo, combo, ptype);
861 }
862
863 gtk_window_present(GTK_WINDOW(cinfo->dlg));
864 }
865
launch_series_maker(GtkWidget * button,call_info * cinfo)866 static void launch_series_maker (GtkWidget *button, call_info *cinfo)
867 {
868 GtkWidget *combo = g_object_get_data(G_OBJECT(button), "combo");
869
870 edit_dialog(GENR, _("add series"),
871 _("Enter name=formula for new series"), NULL,
872 do_fncall_genr, combo,
873 VARCLICK_INSERT_NAME, cinfo->dlg);
874 }
875
launch_scalar_maker(GtkWidget * button,call_info * cinfo)876 static void launch_scalar_maker (GtkWidget *button, call_info *cinfo)
877 {
878 GtkWidget *combo = g_object_get_data(G_OBJECT(button), "combo");
879
880 edit_dialog(GENR, _("add scalar"),
881 _("Enter name=formula for new scalar"), NULL,
882 do_fncall_genr, combo,
883 VARCLICK_INSERT_NAME, cinfo->dlg);
884 }
885
bool_arg_selector(call_info * cinfo,int i,const char * prior_val)886 static GtkWidget *bool_arg_selector (call_info *cinfo, int i,
887 const char *prior_val)
888 {
889 GtkWidget *button;
890 int active;
891
892 if (prior_val != NULL) {
893 active = *prior_val == '1';
894 } else {
895 double deflt = fn_param_default(cinfo->func, i);
896
897 active = !na(deflt) && deflt != 0.0;
898 }
899
900 button = gtk_check_button_new();
901 widget_set_int(button, "argnum", i);
902 g_object_set_data(G_OBJECT(button), "cinfo", cinfo);
903 g_signal_connect(G_OBJECT(button), "toggled",
904 G_CALLBACK(update_bool_arg), cinfo);
905 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
906 cinfo->args[i] = g_strdup((active)? "1" : "0");
907
908 return button;
909 }
910
update_xlist_arg(GtkComboBox * combo,call_info * cinfo)911 static void update_xlist_arg (GtkComboBox *combo,
912 call_info *cinfo)
913 {
914 MODEL *pmod = cinfo->vwin->data;
915 int i = widget_get_int(combo, "argnum");
916 int k = gtk_combo_box_get_active(combo);
917
918 g_free(cinfo->args[i]);
919 cinfo->args[i] = g_strdup_printf("%d", k + 1 + pmod->ifc);
920 }
921
xlist_int_selector(call_info * cinfo,int i)922 static GtkWidget *xlist_int_selector (call_info *cinfo, int i)
923 {
924 MODEL *pmod;
925 GtkWidget *combo;
926 int *xlist;
927
928 if (cinfo->vwin == NULL || cinfo->vwin->data == NULL) {
929 return NULL;
930 }
931
932 pmod = cinfo->vwin->data;
933
934 combo = gtk_combo_box_text_new();
935 widget_set_int(combo, "argnum", i);
936 g_signal_connect(G_OBJECT(combo), "changed",
937 G_CALLBACK(update_xlist_arg), cinfo);
938
939 xlist = gretl_model_get_x_list(pmod);
940
941 if (xlist != NULL) {
942 const char *s;
943 int i, vi;
944
945 for (i=1; i<=xlist[0]; i++) {
946 vi = xlist[i];
947 if (vi > 0) {
948 s = dataset->varname[xlist[i]];
949 combo_box_append_text(combo, s);
950 }
951 }
952 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
953 free(xlist);
954 }
955
956 return combo;
957 }
958
update_mylist_arg(GtkComboBox * combo,call_info * cinfo)959 static void update_mylist_arg (GtkComboBox *combo,
960 call_info *cinfo)
961 {
962 int i = widget_get_int(combo, "argnum");
963 int k = gtk_combo_box_get_active(combo);
964
965 g_free(cinfo->args[i]);
966 cinfo->args[i] = g_strdup_printf("%d", mylist[k+1]);
967 }
968
mylist_int_selector(call_info * cinfo,int i)969 static GtkWidget *mylist_int_selector (call_info *cinfo, int i)
970 {
971 GtkWidget *combo = NULL;
972 const char *lmaker;
973 ufunc *func;
974 int err = 0;
975
976 function_package_get_properties(cinfo->pkg,
977 "list-maker", &lmaker,
978 NULL);
979 if (lmaker == NULL) {
980 err = 1;
981 } else {
982 func = get_function_from_package(lmaker, cinfo->pkg);
983 if (func == NULL) {
984 err = 1;
985 } else {
986 err = lmaker_run(func, cinfo);
987 }
988 }
989
990 if (!err) {
991 const char *s;
992 int j;
993
994 combo = gtk_combo_box_text_new();
995 widget_set_int(combo, "argnum", i);
996 g_signal_connect(G_OBJECT(combo), "changed",
997 G_CALLBACK(update_mylist_arg), cinfo);
998 for (j=1; j<=mylist[0]; j++) {
999 s = dataset->varname[mylist[j]];
1000 combo_box_append_text(combo, s);
1001 }
1002 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1003 }
1004
1005 return combo;
1006 }
1007
update_enum_arg(GtkComboBox * combo,call_info * cinfo)1008 static void update_enum_arg (GtkComboBox *combo, call_info *cinfo)
1009 {
1010 int val = gtk_combo_box_get_active(combo);
1011 int i = widget_get_int(combo, "argnum");
1012
1013 val += widget_get_int(combo, "minv");
1014 g_free(cinfo->args[i]);
1015 cinfo->args[i] = g_strdup_printf("%d", val);
1016 }
1017
maybe_limit_enum(call_info * cinfo,int nvals)1018 static int maybe_limit_enum (call_info *cinfo, int nvals)
1019 {
1020 if (!strcmp(cinfo->pkgname, "lp-mfx") &&
1021 atoi(cinfo->pkgver) > 0 &&
1022 cinfo->vwin != NULL &&
1023 cinfo->vwin->role == VIEW_MODEL) {
1024 MODEL *pmod = cinfo->vwin->data;
1025
1026 if (gretl_model_get_int(pmod, "ordered") ||
1027 gretl_model_get_int(pmod, "multinom")) {
1028 /* exclude the final "per obs" option */
1029 return nvals - 1;
1030 }
1031 }
1032
1033 return nvals;
1034 }
1035
enum_arg_selector(call_info * cinfo,int i,const char ** S,int nvals,int minv,int initv)1036 static GtkWidget *enum_arg_selector (call_info *cinfo, int i,
1037 const char **S, int nvals,
1038 int minv, int initv)
1039 {
1040 GtkWidget *combo;
1041 int j, jmax, jactive;
1042
1043 jmax = maybe_limit_enum(cinfo, nvals);
1044 combo = gtk_combo_box_text_new();
1045 widget_set_int(combo, "argnum", i);
1046 widget_set_int(combo, "minv", minv);
1047 g_signal_connect(G_OBJECT(combo), "changed",
1048 G_CALLBACK(update_enum_arg), cinfo);
1049 for (j=0; j<jmax; j++) {
1050 combo_box_append_text(combo, (const char *) S[j]);
1051 }
1052 jactive = MIN(initv - minv, jmax - 1);
1053 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), jactive);
1054
1055 return combo;
1056 }
1057
spin_arg_selector(call_info * cinfo,int i,int minv,int maxv,int initv,GretlType type)1058 static GtkWidget *spin_arg_selector (call_info *cinfo, int i,
1059 int minv, int maxv, int initv,
1060 GretlType type)
1061 {
1062 GtkAdjustment *adj;
1063 GtkWidget *spin;
1064
1065 adj = (GtkAdjustment *) gtk_adjustment_new(initv, minv, maxv,
1066 1, 1, 0);
1067 if (type == GRETL_TYPE_OBS) {
1068 spin = obs_button_new(adj, dataset, 0);
1069 } else {
1070 spin = gtk_spin_button_new(adj, 1, 0);
1071 }
1072 widget_set_int(spin, "argnum", i);
1073 g_object_set_data(G_OBJECT(spin), "cinfo", cinfo);
1074 g_signal_connect(G_OBJECT(spin), "value-changed",
1075 G_CALLBACK(update_int_arg), cinfo);
1076
1077 cinfo->args[i] = g_strdup_printf("%d", initv);
1078
1079 return spin;
1080 }
1081
int_arg_selector(call_info * cinfo,int i,GretlType type,const char * prior_val)1082 static GtkWidget *int_arg_selector (call_info *cinfo,
1083 int i, GretlType type,
1084 const char *prior_val)
1085 {
1086 double dminv = fn_param_minval(cinfo->func, i);
1087 double dmaxv = fn_param_maxval(cinfo->func, i);
1088 double deflt = fn_param_default(cinfo->func, i);
1089 int minv, maxv, initv = 0;
1090
1091 if (type == GRETL_TYPE_OBS) {
1092 /* the incoming vals will be 1-based */
1093 minv = (na(dminv) || dminv < 1)? 0 : (int) dminv - 1;
1094 maxv = (na(dmaxv) || dmaxv > dataset->n)?
1095 (dataset->n - 1) : (int) dmaxv - 1;
1096 } else {
1097 minv = (na(dminv))? INT_MIN : (int) dminv;
1098 maxv = (na(dmaxv))? INT_MAX : (int) dmaxv;
1099 }
1100
1101 if (prior_val != NULL) {
1102 initv = atoi(prior_val);
1103 } else if (!na(deflt)) {
1104 initv = (int) deflt;
1105 } else if (!na(dminv)) {
1106 initv = (int) dminv;
1107 }
1108
1109 if (type == GRETL_TYPE_INT && !na(dminv) && !na(dmaxv)) {
1110 const char **S;
1111 int nvals;
1112
1113 S = fn_param_value_labels(cinfo->func, i, &nvals);
1114 if (S != NULL) {
1115 return enum_arg_selector(cinfo, i, S, nvals, minv, initv);
1116 }
1117 }
1118
1119 return spin_arg_selector(cinfo, i, minv, maxv, initv, type);
1120 }
1121
double_arg_selector(call_info * cinfo,int i,const char * prior_val)1122 static GtkWidget *double_arg_selector (call_info *cinfo, int i,
1123 const char *prior_val)
1124 {
1125 double minv = fn_param_minval(cinfo->func, i);
1126 double maxv = fn_param_maxval(cinfo->func, i);
1127 double deflt = fn_param_default(cinfo->func, i);
1128 double step = fn_param_step(cinfo->func, i);
1129 GtkAdjustment *adj;
1130 GtkWidget *spin;
1131 gchar *p, *tmp;
1132 int ndec = 0;
1133
1134 tmp = g_strdup_printf("%g", maxv - step);
1135 p = strchr(tmp, '.');
1136 if (p == NULL) {
1137 p = strchr(tmp, ',');
1138 }
1139 if (p != NULL) {
1140 ndec = strlen(p + 1);
1141 }
1142 g_free(tmp);
1143
1144 if (prior_val != NULL) {
1145 /* locale? */
1146 deflt = atof(prior_val);
1147 }
1148
1149 if (deflt > maxv) {
1150 /* note that default may be NADBL */
1151 deflt = minv;
1152 }
1153
1154 adj = (GtkAdjustment *) gtk_adjustment_new(deflt, minv, maxv,
1155 step, step, 0);
1156 spin = gtk_spin_button_new(adj, 1, ndec);
1157 widget_set_int(spin, "argnum", i);
1158 g_object_set_data(G_OBJECT(spin), "cinfo", cinfo);
1159 g_signal_connect(G_OBJECT(spin), "value-changed",
1160 G_CALLBACK(update_double_arg), cinfo);
1161 cinfo->args[i] = g_strdup_printf("%g", deflt);
1162
1163 return spin;
1164 }
1165
1166 /* see if the variable named @name of type @ptype
1167 has already been set as the default argument in
1168 an "upstream" combo argument selector
1169 */
1170
already_set_as_default(call_info * cinfo,const char * name,int ptype)1171 static int already_set_as_default (call_info *cinfo,
1172 const char *name,
1173 int ptype)
1174 {
1175 GList *slist;
1176 int ret = 0;
1177
1178 if (series_arg(ptype)) {
1179 slist = g_list_first(cinfo->vsels);
1180 } else if (matrix_arg(ptype)) {
1181 slist = g_list_first(cinfo->msels);
1182 } else if (bundle_arg(ptype)) {
1183 slist = g_list_first(cinfo->bsels);
1184 } else if (array_arg(ptype)) {
1185 slist = g_list_first(cinfo->asels);
1186 } else if (scalar_arg(ptype)) {
1187 slist = g_list_first(cinfo->ssels);
1188 } else if (ptype == GRETL_TYPE_LIST) {
1189 slist = g_list_first(cinfo->lsels);
1190 } else {
1191 return 0;
1192 }
1193
1194 while (slist != NULL && !ret) {
1195 GtkComboBox *sel = GTK_COMBO_BOX(slist->data);
1196 gchar *s = combo_box_get_active_text(sel);
1197
1198 if (!strcmp(s, name)) {
1199 ret = 1;
1200 } else {
1201 slist = g_list_next(slist);
1202 }
1203 g_free(s);
1204 }
1205
1206 return ret;
1207 }
1208
has_single_arg_of_type(call_info * cinfo,GretlType type)1209 static int has_single_arg_of_type (call_info *cinfo,
1210 GretlType type)
1211 {
1212 int i, n = 0;
1213
1214 for (i=0; i<cinfo->n_params; i++) {
1215 if (fn_param_type(cinfo->func, i) == type) {
1216 n++;
1217 }
1218 }
1219
1220 return n == 1;
1221 }
1222
1223 /* Try to be somewhat clever in selecting the default values to show
1224 in function-argument drop-down "combo" selectors.
1225
1226 Heuristics: (a) when a series is wanted, it's more likely to be a
1227 stochastic series rather than (e.g.) a time trend or panel group
1228 variable, so we try to avoid the latter as defaults; and (b) it's
1229 unlikely that the user wants to select the same named variable in
1230 more than one argument slot, so we try to avoid setting duplicate
1231 defaults.
1232
1233 Special case: the function has exactly one series argument, and
1234 a single series is selected in the main gretl window: in that
1235 case we pre-select that series.
1236 */
1237
arg_combo_set_default(call_info * cinfo,GtkComboBox * combo,GList * list,int ptype)1238 static void arg_combo_set_default (call_info *cinfo,
1239 GtkComboBox *combo,
1240 GList *list,
1241 int ptype)
1242 {
1243 GList *tmp = g_list_first(list);
1244 const char *targname = NULL;
1245 int i, v, k = 0;
1246
1247 if (ptype == GRETL_TYPE_SERIES) {
1248 if (has_single_arg_of_type(cinfo, ptype)) {
1249 v = mdata_active_var();
1250 if (v > 0 && probably_stochastic(v)) {
1251 targname = dataset->varname[v];
1252 }
1253 }
1254 } else if (ptype == GRETL_TYPE_LIST) {
1255 if (has_single_arg_of_type(cinfo, ptype) &&
1256 mdata_selection_count() > 1) {
1257 targname = SELNAME;
1258 tmp = g_list_prepend(tmp, SELNAME);
1259 }
1260 }
1261
1262 for (i=0; tmp != NULL; i++) {
1263 gchar *name = tmp->data;
1264 int ok = 0;
1265
1266 if (targname != NULL) {
1267 ok = strcmp(name, targname) == 0;
1268 } else if (series_arg(ptype)) {
1269 v = current_series_index(dataset, name);
1270 if (v > 0 && probably_stochastic(v)) {
1271 ok = !already_set_as_default(cinfo, name, ptype);
1272 }
1273 } else {
1274 ok = !already_set_as_default(cinfo, name, ptype);
1275 }
1276
1277 if (ok) {
1278 k = i;
1279 break;
1280 } else {
1281 tmp = g_list_next(tmp);
1282 }
1283 }
1284
1285 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), k);
1286 }
1287
1288 /* create an argument selector widget in the form of a
1289 GtkComboBox, with an entry field plus a drop-down
1290 list (which may initially be empty)
1291 */
1292
combo_arg_selector(call_info * cinfo,int ptype,int i,const char * prior_val)1293 static GtkWidget *combo_arg_selector (call_info *cinfo, int ptype, int i,
1294 const char *prior_val)
1295 {
1296 GList *list = NULL;
1297 GtkWidget *combo;
1298 GtkWidget *entry;
1299 int k = 0, null_OK = 0;
1300
1301 combo = combo_box_text_new_with_entry();
1302 entry = gtk_bin_get_child(GTK_BIN(combo));
1303 g_object_set_data(G_OBJECT(entry), "cinfo", cinfo);
1304 widget_set_int(combo, "argnum", i);
1305 g_signal_connect(G_OBJECT(combo), "changed",
1306 G_CALLBACK(update_arg), cinfo);
1307 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
1308
1309 if (fn_param_optional(cinfo->func, i)) {
1310 null_OK = 1;
1311 widget_set_int(combo, "null_OK", 1);
1312 }
1313
1314 list = get_selection_list(ptype);
1315 if (list != NULL) {
1316 set_combo_box_strings_from_list(combo, list);
1317 arg_combo_set_default(cinfo, GTK_COMBO_BOX(combo),
1318 list, ptype);
1319 k = g_list_length(list);
1320 g_list_free(list);
1321 }
1322
1323 if (null_OK) {
1324 combo_box_append_text(combo, "null");
1325 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), k);
1326 }
1327
1328 if (prior_val != NULL) {
1329 gtk_entry_set_text(GTK_ENTRY(entry), prior_val);
1330 } else if (ptype == GRETL_TYPE_INT) {
1331 double x = fn_param_default(cinfo->func, i);
1332
1333 if (!na(x)) {
1334 gchar *tmp = g_strdup_printf("%g", x);
1335
1336 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1337 g_free(tmp);
1338 }
1339 } else if (ptype == GRETL_TYPE_DOUBLE &&
1340 fn_param_has_default(cinfo->func, i)) {
1341 double x = fn_param_default(cinfo->func, i);
1342
1343 if (na(x)) {
1344 gtk_entry_set_text(GTK_ENTRY(entry), "NA");
1345 } else {
1346 gchar *tmp = g_strdup_printf("%g", x);
1347
1348 gtk_entry_set_text(GTK_ENTRY(entry), tmp);
1349 g_free(tmp);
1350 }
1351 }
1352
1353 return combo;
1354 }
1355
add_table_header(GtkWidget * tbl,gchar * txt,int cols,int r0,int ypad)1356 static void add_table_header (GtkWidget *tbl, gchar *txt,
1357 int cols, int r0, int ypad)
1358 {
1359 GtkWidget *label = gtk_label_new(txt);
1360 GtkWidget *align = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
1361
1362 gtk_container_add(GTK_CONTAINER(align), label);
1363 gtk_table_attach(GTK_TABLE(tbl), align, 0, cols, r0, r0 + 1,
1364 GTK_FILL, GTK_FILL, 5, ypad);
1365 }
1366
add_table_cell(GtkWidget * tbl,GtkWidget * w,int c0,int c1,int r0)1367 static void add_table_cell (GtkWidget *tbl, GtkWidget *w,
1368 int c0, int c1, int r0)
1369 {
1370 gtk_table_attach(GTK_TABLE(tbl), w, c0, c1, r0, r0 + 1,
1371 GTK_FILL, GTK_FILL, 5, 3);
1372 }
1373
add_object_button(int ptype,GtkWidget * combo,const char * parname)1374 static GtkWidget *add_object_button (int ptype, GtkWidget *combo,
1375 const char *parname)
1376 {
1377 GtkWidget *img = gtk_image_new_from_stock(GTK_STOCK_ADD,
1378 GTK_ICON_SIZE_MENU);
1379 GtkWidget *button = gtk_button_new();
1380
1381 gtk_container_add(GTK_CONTAINER(button), img);
1382 g_object_set_data(G_OBJECT(button), "combo", combo);
1383 if (parname != NULL) {
1384 /* FIXME is the cast OK here? */
1385 g_object_set_data(G_OBJECT(button), "parname", (char *) parname);
1386 }
1387
1388 if (series_arg(ptype)) {
1389 gretl_tooltips_add(button, _("New variable"));
1390 } else if (matrix_arg(ptype)) {
1391 gretl_tooltips_add(button, _("Define matrix"));
1392 } else if (ptype == GRETL_TYPE_LIST) {
1393 gretl_tooltips_add(button, _("Define list"));
1394 }
1395
1396 return button;
1397 }
1398
spinnable_scalar_arg(call_info * cinfo,int i)1399 static int spinnable_scalar_arg (call_info *cinfo, int i)
1400 {
1401 const ufunc *func = cinfo->func;
1402 double mi = fn_param_minval(func, i);
1403 double ma = fn_param_maxval(func, i);
1404 double s = fn_param_step(func, i);
1405
1406 return !na(mi) && !na(ma) && !na(s);
1407 }
1408
set_close_on_OK(GtkWidget * b,gpointer p)1409 static void set_close_on_OK (GtkWidget *b, gpointer p)
1410 {
1411 close_on_OK = button_is_active(b);
1412 }
1413
set_allow_full_data(GtkWidget * b,gpointer p)1414 static void set_allow_full_data (GtkWidget *b, gpointer p)
1415 {
1416 allow_full_data = button_is_active(b);
1417 allow_full_data_access(allow_full_data);
1418 }
1419
cinfo_show_return(call_info * c)1420 static int cinfo_show_return (call_info *c)
1421 {
1422 if (c->rettype == GRETL_TYPE_NONE ||
1423 c->rettype == GRETL_TYPE_VOID) {
1424 return 0;
1425 } else if (c->rettype == GRETL_TYPE_BUNDLE &&
1426 (c->flags & SHOW_GUI_MAIN)) {
1427 return 0;
1428 } else {
1429 return 1;
1430 }
1431 }
1432
cinfo_pkg_title(call_info * cinfo)1433 static gchar *cinfo_pkg_title (call_info *cinfo)
1434 {
1435 return g_strdup_printf("gretl: %s %s", cinfo->pkgname,
1436 cinfo->pkgver);
1437 }
1438
function_call_dialog(call_info * cinfo)1439 static int function_call_dialog (call_info *cinfo)
1440 {
1441 GtkWidget *button, *label;
1442 GtkWidget *sel, *tbl = NULL;
1443 GtkWidget *vbox, *hbox, *bbox;
1444 arglist *alist = NULL;
1445 gchar *txt;
1446 int trows = 0, tcols = 0;
1447 int show_ret;
1448 int i, row;
1449 int err;
1450
1451 if (open_fncall_dlg != NULL) {
1452 gtk_window_present(GTK_WINDOW(open_fncall_dlg));
1453 return 0;
1454 }
1455
1456 err = cinfo_args_init(cinfo);
1457 if (err) {
1458 gui_errmsg(err);
1459 return err;
1460 }
1461
1462 cinfo->dlg = gretl_gtk_window();
1463 txt = cinfo_pkg_title(cinfo);
1464 gtk_window_set_title(GTK_WINDOW(cinfo->dlg), txt);
1465 g_free(txt);
1466 gretl_emulated_dialog_add_structure(cinfo->dlg, &vbox, &bbox);
1467 open_fncall_dlg = cinfo->dlg;
1468 g_signal_connect(G_OBJECT(cinfo->dlg), "destroy",
1469 G_CALLBACK(fncall_dialog_destruction), cinfo);
1470
1471 /* above table: label or name of function being called */
1472 cinfo->top_hbox = hbox = label_hbox(cinfo, vbox);
1473
1474 show_ret = cinfo_show_return(cinfo);
1475
1476 if (cinfo->n_params > 0) {
1477 tcols = 3; /* label, selector, add-button */
1478 trows = cinfo->n_params + 1;
1479 if (show_ret) {
1480 trows += 4;
1481 }
1482 alist = arglist_lookup(cinfo->pkgname, cinfo->func);
1483 } else if (show_ret) {
1484 tcols = 2;
1485 trows = 3;
1486 }
1487
1488 if (trows > 0 && tcols > 0) {
1489 tbl = gtk_table_new(trows, tcols, FALSE);
1490 }
1491
1492 row = 0; /* initialize writing row */
1493
1494 for (i=0; i<cinfo->n_params; i++) {
1495 const char *desc = fn_param_descrip(cinfo->func, i);
1496 const char *parname = fn_param_name(cinfo->func, i);
1497 const char *prior_val = NULL;
1498 int ptype = fn_param_type(cinfo->func, i);
1499 int spinnable = 0;
1500 gchar *argtxt;
1501
1502 if (i == 0 && cinfo->n_params > 1) {
1503 add_table_header(tbl, _("Select arguments:"), tcols, row, 5);
1504 }
1505
1506 if (alist != NULL) {
1507 prior_val = arglist_lookup_val(alist, i);
1508 }
1509
1510 row++;
1511
1512 if (ptype == GRETL_TYPE_DOUBLE) {
1513 spinnable = spinnable_scalar_arg(cinfo, i);
1514 }
1515
1516 /* label for name (and maybe type) of argument, using
1517 descriptive string if available */
1518 if (ptype == GRETL_TYPE_INT ||
1519 ptype == GRETL_TYPE_BOOL ||
1520 ptype == GRETL_TYPE_OBS ||
1521 spinnable) {
1522 argtxt = g_strdup_printf("%s",
1523 (desc != NULL)? _(desc) :
1524 parname);
1525 } else {
1526 const char *astr = gretl_type_get_name(ptype);
1527
1528 if (desc != NULL && strstr(desc, astr)) {
1529 argtxt = g_strdup_printf("%s", _(desc));
1530 } else {
1531 argtxt = g_strdup_printf("%s (%s)",
1532 (desc != NULL)? _(desc) :
1533 parname, astr);
1534 }
1535 }
1536
1537 label = gtk_label_new(argtxt);
1538 g_free(argtxt);
1539 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1540 add_table_cell(tbl, label, 0, 1, row);
1541
1542 /* make the appropriate type of selector widget */
1543
1544 if (fn_param_uses_xlist(cinfo->func, i)) {
1545 sel = xlist_int_selector(cinfo, i);
1546 } else if (fn_param_uses_mylist(cinfo->func, i)) {
1547 sel = mylist_int_selector(cinfo, i);
1548 } else if (ptype == GRETL_TYPE_BOOL) {
1549 sel = bool_arg_selector(cinfo, i, prior_val);
1550 } else if (ptype == GRETL_TYPE_INT ||
1551 ptype == GRETL_TYPE_OBS) {
1552 sel = int_arg_selector(cinfo, i, ptype, prior_val);
1553 } else if (spinnable) {
1554 sel = double_arg_selector(cinfo, i, prior_val);
1555 } else {
1556 sel = combo_arg_selector(cinfo, ptype, i, prior_val);
1557 }
1558
1559 if (sel == NULL) {
1560 /* panic! */
1561 err = 1;
1562 break;
1563 }
1564
1565 add_table_cell(tbl, sel, 1, 2, row);
1566
1567 /* hook up signals and "+" add buttons for the
1568 selectors for most types of arguments (though
1569 not for bool and spinner-type args)
1570 */
1571
1572 if (series_arg(ptype)) {
1573 cinfo->vsels = g_list_append(cinfo->vsels, sel);
1574 widget_set_int(sel, "ptype", GRETL_TYPE_SERIES);
1575 button = add_object_button(ptype, sel, parname);
1576 add_table_cell(tbl, button, 2, 3, row);
1577 g_signal_connect(G_OBJECT(button), "clicked",
1578 G_CALLBACK(launch_series_maker),
1579 cinfo);
1580 } else if (scalar_arg(ptype) && !spinnable) {
1581 cinfo->ssels = g_list_append(cinfo->ssels, sel);
1582 widget_set_int(sel, "ptype", GRETL_TYPE_DOUBLE);
1583 button = add_object_button(ptype, sel, parname);
1584 add_table_cell(tbl, button, 2, 3, row);
1585 g_signal_connect(G_OBJECT(button), "clicked",
1586 G_CALLBACK(launch_scalar_maker),
1587 cinfo);
1588 } else if (matrix_arg(ptype)) {
1589 cinfo->msels = g_list_append(cinfo->msels, sel);
1590 button = add_object_button(ptype, sel, parname);
1591 add_table_cell(tbl, button, 2, 3, row);
1592 g_signal_connect(G_OBJECT(button), "clicked",
1593 G_CALLBACK(launch_matrix_maker),
1594 cinfo);
1595 } else if (bundle_arg(ptype)) {
1596 cinfo->bsels = g_list_append(cinfo->bsels, sel);
1597 } else if (array_arg(ptype)) {
1598 cinfo->asels = g_list_append(cinfo->asels, sel);
1599 } else if (ptype == GRETL_TYPE_LIST) {
1600 GtkWidget *entry = gtk_bin_get_child(GTK_BIN(sel));
1601
1602 cinfo->lsels = g_list_append(cinfo->lsels, sel);
1603 button = add_object_button(ptype, sel, parname);
1604 add_table_cell(tbl, button, 2, 3, row);
1605 widget_set_int(entry, "argnum", i);
1606 g_object_set_data(G_OBJECT(button), "cinfo", cinfo);
1607 g_object_set_data(G_OBJECT(entry), "sel", sel);
1608 g_signal_connect(G_OBJECT(button), "clicked",
1609 G_CALLBACK(launch_list_maker),
1610 entry);
1611 }
1612 }
1613
1614 if (err) {
1615 /* failed to build all selectors */
1616 gtk_widget_destroy(tbl);
1617 gtk_widget_destroy(cinfo->dlg);
1618 errbox("Setup of function failed");
1619 return err;
1620 }
1621
1622 if (show_ret) {
1623 /* selector/entry for return value */
1624 GtkWidget *child;
1625 GList *list = NULL;
1626
1627 if (cinfo->n_params > 0) {
1628 /* separator row */
1629 add_table_header(tbl, "", tcols, ++row, 0);
1630 }
1631
1632 add_table_header(tbl, _("Assign return value (optional):"),
1633 tcols, ++row, 5);
1634
1635 label = gtk_label_new(_("selection (or new variable)"));
1636 add_table_cell(tbl, label, 1, 2, ++row);
1637
1638 label = gtk_label_new(gretl_type_get_name(cinfo->rettype));
1639 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1640 add_table_cell(tbl, label, 0, 1, ++row);
1641
1642 sel = combo_box_text_new_with_entry();
1643 g_signal_connect(G_OBJECT(sel), "changed",
1644 G_CALLBACK(update_return), cinfo);
1645 list = get_selection_list(cinfo->rettype);
1646 if (list != NULL) {
1647 set_combo_box_strings_from_list(sel, list);
1648 g_list_free(list);
1649 }
1650
1651 /* prepend blank option and select it */
1652 combo_box_prepend_text(sel, "");
1653 gtk_combo_box_set_active(GTK_COMBO_BOX(sel), 0);
1654 child = gtk_bin_get_child(GTK_BIN(sel));
1655 gtk_entry_set_activates_default(GTK_ENTRY(child), TRUE);
1656 add_table_cell(tbl, sel, 1, 2, row); /* same row as above */
1657 }
1658
1659 if (tbl != NULL) {
1660 /* the table is complete: pack it now */
1661 gtk_box_pack_start(GTK_BOX(vbox), tbl, FALSE, FALSE, 0);
1662 }
1663
1664 if ((cinfo->flags & DATA_ACCESS) && sample_size(dataset) < dataset->n) {
1665 /* "allow data access" option button */
1666 hbox = gtk_hbox_new(FALSE, 5);
1667 button = gtk_check_button_new_with_label(_("allow access to out-of-sample data"));
1668 g_signal_connect(G_OBJECT(button), "toggled",
1669 G_CALLBACK(set_allow_full_data), NULL);
1670 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
1671 allow_full_data);
1672 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
1673 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1674 }
1675
1676 /* "close on exec" option button */
1677 hbox = gtk_hbox_new(FALSE, 5);
1678 button = gtk_check_button_new_with_label(_("close this dialog on \"OK\""));
1679 g_signal_connect(G_OBJECT(button), "toggled",
1680 G_CALLBACK(set_close_on_OK), NULL);
1681 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
1682 close_on_OK);
1683 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
1684 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1685
1686 /* Close button */
1687 button = close_button(bbox);
1688 g_signal_connect(G_OBJECT (button), "clicked",
1689 G_CALLBACK(fncall_close), cinfo);
1690
1691 /* "OK" button */
1692 button = ok_button(bbox);
1693 g_signal_connect(G_OBJECT(button), "clicked",
1694 G_CALLBACK(fncall_exec_callback), cinfo);
1695 gtk_widget_grab_default(button);
1696
1697 /* Help button */
1698 button = context_help_button(bbox, -1);
1699 g_signal_connect(G_OBJECT(button), "clicked",
1700 G_CALLBACK(fncall_help), cinfo);
1701
1702 if (cinfo->vwin != NULL) {
1703 gtk_window_set_transient_for(GTK_WINDOW(cinfo->dlg),
1704 GTK_WINDOW(cinfo->vwin->main));
1705 }
1706
1707 gtk_widget_show_all(cinfo->dlg);
1708
1709 return 0;
1710 }
1711
1712 /* called when defining a matrix for use as an argument:
1713 @dlg will be the function call dialog
1714 */
1715
get_fncall_param_info(GtkWidget * dlg,int * series_ok,char ** pname)1716 void get_fncall_param_info (GtkWidget *dlg, int *series_ok,
1717 char **pname)
1718 {
1719 if (dlg == NULL) {
1720 return;
1721 }
1722
1723 if (series_ok != NULL) {
1724 *series_ok = !widget_get_int(dlg, "matrix-no-series");
1725 }
1726
1727 if (pname != NULL) {
1728 GtkWidget *button =
1729 g_object_get_data(G_OBJECT(dlg), "button");
1730
1731 if (button != NULL) {
1732 char *name = g_object_get_data(G_OBJECT(button),
1733 "parname");
1734
1735 if (name != NULL &&
1736 current_series_index(dataset, name) < 0 &&
1737 gretl_get_object_by_name(name) == NULL) {
1738 /* OK, not the name of current object, so
1739 offer it as default */
1740 *pname = g_strdup(name);
1741 }
1742 }
1743 }
1744 }
1745
function_data_check(call_info * cinfo,windata_t * vwin,const char * path)1746 static int function_data_check (call_info *cinfo,
1747 windata_t *vwin,
1748 const char *path)
1749 {
1750 int err = 0;
1751
1752 if (dataset != NULL && dataset->v > 0) {
1753 ; /* OK, we have data */
1754 } else if (cinfo->dreq != FN_NODATA_OK) {
1755 /* The package requires a dataset but no dataset
1756 is loaded: this error should have been caught
1757 earlier?
1758 */
1759 err = 1;
1760 } else {
1761 /* check the particular function being called:
1762 this is potentially relevant if we're coming
1763 from the gfn browser, trying to execute the
1764 default function of a package. It's possible
1765 that the package as such does not require a
1766 dataset but its default function does --
1767 though that is arguably somewhat anomalous.
1768 */
1769 int i;
1770
1771 for (i=0; i<cinfo->n_params; i++) {
1772 int type = fn_param_type(cinfo->func, i);
1773
1774 if (type == GRETL_TYPE_SERIES ||
1775 type == GRETL_TYPE_LIST ||
1776 type == GRETL_TYPE_SERIES_REF) {
1777 err = 1;
1778 break;
1779 }
1780 }
1781 }
1782
1783 if (err) {
1784 /* 2018-02-12: was warnbox(_("Please open a data file first")); */
1785 maybe_open_sample_script(cinfo, vwin, path);
1786 }
1787
1788 return err;
1789 }
1790
1791 /* detect the case where we need a "pointer" variable but
1792 have been given a scalar or matrix constant
1793 */
1794
should_addressify_var(call_info * cinfo,int i)1795 static int should_addressify_var (call_info *cinfo, int i)
1796 {
1797 char *numchars = "0123456789+-.,";
1798 int t = fn_param_type(cinfo->func, i);
1799 gchar *s = cinfo->args[i];
1800
1801 return (t == GRETL_TYPE_SCALAR_REF && strchr(numchars, *s)) ||
1802 (t == GRETL_TYPE_MATRIX_REF && *s == '{');
1803 }
1804
maybe_add_amp(call_info * cinfo,int i,PRN * prn,int * add)1805 static int maybe_add_amp (call_info *cinfo, int i, PRN *prn, int *add)
1806 {
1807 int t = fn_param_type(cinfo->func, i);
1808 gchar *name = cinfo->args[i];
1809 int err = 0;
1810
1811 *add = 0;
1812
1813 if (!gretl_ref_type(t)) {
1814 return 0;
1815 }
1816
1817 if (*name == '&' || !strcmp(name, "null")) {
1818 return 0;
1819 }
1820
1821 /* Handle cases where an "indirect return" variable
1822 does not yet exist: we need to declare it.
1823 */
1824
1825 if (t == GRETL_TYPE_MATRIX_REF) {
1826 if (get_matrix_by_name(name) == NULL) {
1827 gretl_matrix *m = gretl_null_matrix_new();
1828
1829 if (m == NULL) {
1830 err = E_ALLOC;
1831 } else {
1832 err = user_var_add_or_replace(name,
1833 GRETL_TYPE_MATRIX,
1834 m);
1835 }
1836 if (!err) {
1837 pprintf(prn, "? matrix %s\n", name);
1838 }
1839 }
1840 } else if (t == GRETL_TYPE_SERIES_REF) {
1841 if (current_series_index(dataset, name) < 0) {
1842 err = generate(name, dataset, GRETL_TYPE_SERIES,
1843 OPT_Q, NULL);
1844 if (!err) {
1845 pprintf(prn, "? series %s\n", name);
1846 }
1847 }
1848 }
1849
1850 if (!err) {
1851 *add = 1;
1852 }
1853
1854 return err;
1855 }
1856
needs_quoting(call_info * cinfo,int i)1857 static int needs_quoting (call_info *cinfo, int i)
1858 {
1859 int t = fn_param_type(cinfo->func, i);
1860 gchar *s = cinfo->args[i];
1861
1862 return (t == GRETL_TYPE_STRING &&
1863 strcmp(s, "null") &&
1864 get_string_by_name(s) == NULL &&
1865 *s != '"');
1866 }
1867
pre_process_args(call_info * cinfo,int * autolist,PRN * prn)1868 static int pre_process_args (call_info *cinfo, int *autolist,
1869 PRN *prn)
1870 {
1871 char auxline[MAXLINE];
1872 char auxname[VNAMELEN+2];
1873 int i, add = 0, err = 0;
1874
1875 for (i=0; i<cinfo->n_params && !err; i++) {
1876 if (should_addressify_var(cinfo, i)) {
1877 sprintf(auxname, "FNARG%d", i + 1);
1878 sprintf(auxline, "%s=%s", auxname, cinfo->args[i]);
1879 err = generate(auxline, dataset, GRETL_TYPE_ANY,
1880 OPT_NONE, NULL);
1881 if (!err) {
1882 g_free(cinfo->args[i]);
1883 cinfo->args[i] = g_strdup(auxname);
1884 pprintf(prn, "? %s\n", auxline);
1885 }
1886 }
1887
1888 err = maybe_add_amp(cinfo, i, prn, &add);
1889
1890 if (add) {
1891 strcpy(auxname, "&");
1892 strncat(auxname, cinfo->args[i], VNAMELEN);
1893 g_free(cinfo->args[i]);
1894 cinfo->args[i] = g_strdup(auxname);
1895 } else if (needs_quoting(cinfo, i)) {
1896 sprintf(auxname, "\"%s\"", cinfo->args[i]);
1897 g_free(cinfo->args[i]);
1898 cinfo->args[i] = g_strdup(auxname);
1899 }
1900
1901 if (fn_param_type(cinfo->func, i) == GRETL_TYPE_OBS) {
1902 /* convert integer value from 0- to 1-based */
1903 int val = atoi(cinfo->args[i]) + 1;
1904
1905 g_free(cinfo->args[i]);
1906 cinfo->args[i] = g_strdup_printf("%d", val);
1907 } else if (fn_param_type(cinfo->func, i) == GRETL_TYPE_LIST) {
1908 /* do we have an automatic list arg? */
1909 if (!strcmp(cinfo->args[i], SELNAME)) {
1910 user_var_add(AUTOLIST, GRETL_TYPE_LIST,
1911 main_window_selection_as_list());
1912 g_free(cinfo->args[i]);
1913 cinfo->args[i] = g_strdup(AUTOLIST);
1914 *autolist = i;
1915 }
1916 }
1917 }
1918
1919 return err;
1920 }
1921
set_genr_model_from_vwin(windata_t * vwin)1922 static void set_genr_model_from_vwin (windata_t *vwin)
1923 {
1924 GretlObjType type = GRETL_OBJ_EQN;
1925
1926 if (vwin->role == VAR || vwin->role == VECM) {
1927 type = GRETL_OBJ_VAR;
1928 } else if (vwin->role == SYSTEM) {
1929 type = GRETL_OBJ_SYS;
1930 }
1931
1932 set_genr_model(vwin->data, type);
1933 }
1934
1935 /* Compose the command line that calls a packaged function with the
1936 appropriate arguments, if any, and possible assignment of the
1937 return value, if any.
1938 */
1939
compose_fncall_line(char * line,call_info * cinfo,const char * funname,char ** tmpname,int * grab_bundle,int * dummy_list)1940 static void compose_fncall_line (char *line,
1941 call_info *cinfo,
1942 const char *funname,
1943 char **tmpname,
1944 int *grab_bundle,
1945 int *dummy_list)
1946 {
1947 arglist *alist;
1948
1949 alist = arglist_lookup(cinfo->pkgname, cinfo->func);
1950
1951 if (alist == NULL) {
1952 alist = arglist_new(cinfo->pkgname, cinfo->func,
1953 cinfo->n_params);
1954 }
1955
1956 *line = '\0';
1957
1958 if (cinfo->rettype == GRETL_TYPE_LIST && cinfo->ret == NULL) {
1959 strcpy(line, "list " DUMLIST " = ");
1960 *dummy_list = 1;
1961 } else if (cinfo->ret != NULL) {
1962 strcat(line, cinfo->ret);
1963 strcat(line, " = ");
1964 } else if (cinfo->rettype == GRETL_TYPE_BUNDLE) {
1965 /* the function offers a bundle return but this has not been
1966 assigned by the user; make a special arrangement to grab
1967 the bundle for GUI purposes
1968 */
1969 *tmpname = temp_name_for_bundle();
1970 strcat(line, *tmpname);
1971 strcat(line, " = ");
1972 *grab_bundle = 1;
1973 }
1974
1975 strcat(line, funname);
1976 strcat(line, "(");
1977
1978 if (cinfo->args != NULL) {
1979 int i;
1980
1981 for (i=0; i<cinfo->n_params; i++) {
1982 strcat(line, cinfo->args[i]);
1983 if (alist != NULL) {
1984 arglist_record_arg(alist, i, cinfo->args[i]);
1985 }
1986 if (i < cinfo->n_params - 1) {
1987 strcat(line, ", ");
1988 }
1989 }
1990 }
1991
1992 strcat(line, ")");
1993 }
1994
real_GUI_function_call(call_info * cinfo,PRN * prn)1995 static int real_GUI_function_call (call_info *cinfo, PRN *prn)
1996 {
1997 windata_t *outwin = NULL;
1998 ExecState state;
1999 char fnline[MAXLINE];
2000 char *tmpname = NULL;
2001 const char *funname;
2002 const char *title;
2003 gretl_bundle *bundle = NULL;
2004 int grab_bundle = 0;
2005 int dummy_list = 0;
2006 int show = 1;
2007 int err = 0;
2008
2009 funname = user_function_name_by_index(cinfo->iface);
2010 title = cinfo->label != NULL ? cinfo->label : funname;
2011
2012 compose_fncall_line(fnline, cinfo, funname,
2013 &tmpname, &grab_bundle,
2014 &dummy_list);
2015
2016 /* FIXME: the following conditionality may be wrong? */
2017
2018 if (!grab_bundle && strncmp(funname, "GUI", 3)) {
2019 pprintf(prn, "? %s\n", fnline);
2020 }
2021
2022 #if FCDEBUG
2023 fprintf(stderr, "fnline: %s\n", fnline);
2024 #endif
2025
2026 /* note: gretl_exec_state_init zeros the first byte of its
2027 'line' member
2028 */
2029 gretl_exec_state_init(&state, SCRIPT_EXEC, NULL, get_lib_cmd(),
2030 model, prn);
2031 state.line = fnline;
2032
2033 if (cinfo->flags & MODEL_CALL) {
2034 set_genr_model_from_vwin(cinfo->vwin);
2035 }
2036
2037 show = !user_func_is_noprint(cinfo->func);
2038
2039 #if FCDEBUG
2040 fprintf(stderr, "show = %d, grab_bundle = %d\n", show, grab_bundle);
2041 #endif
2042
2043 if (show) {
2044 /* allow the "flush" mechanism to operate */
2045 if (close_on_OK && cinfo->dlg != NULL) {
2046 gtk_widget_hide(cinfo->dlg);
2047 }
2048 err = exec_line_with_output_handler(&state, dataset,
2049 title, &outwin);
2050 } else {
2051 /* execute "invisibly" */
2052 GtkWidget *ctop = NULL;
2053 GdkWindow *cwin = NULL;
2054 int modal = 0;
2055
2056 if (cinfo->dlg != NULL) {
2057 /* set modality */
2058 ctop = gtk_widget_get_toplevel(cinfo->dlg);
2059 if (GTK_IS_WINDOW(ctop)) {
2060 gtk_window_set_modal(GTK_WINDOW(ctop), TRUE);
2061 modal = 1;
2062 cwin = gtk_widget_get_window(ctop);
2063 }
2064 }
2065
2066 set_wait_cursor(&cwin);
2067 err = gui_exec_line(&state, dataset, NULL);
2068 unset_wait_cursor(cwin);
2069
2070 if (cinfo->dlg != NULL) {
2071 /* unset modality */
2072 if (modal) {
2073 gtk_window_set_modal(GTK_WINDOW(ctop), FALSE);
2074 }
2075 if (close_on_OK) {
2076 gtk_widget_hide(cinfo->dlg);
2077 }
2078 }
2079 }
2080
2081 if (dummy_list) {
2082 /* handle use of dummy list to get series saved */
2083 int *L = get_list_by_name(DUMLIST);
2084
2085 if (L != NULL && L[0] > 0) {
2086 set_dataset_is_changed(dataset, 1);
2087 }
2088 user_var_delete_by_name(DUMLIST, NULL);
2089 }
2090
2091 if (!err && strstr(fnline, AUTOLIST) == NULL) {
2092 int ID = 0;
2093
2094 if (cinfo->flags & MODEL_CALL) {
2095 ID = get_genr_model_ID();
2096 }
2097
2098 maybe_record_include(cinfo->pkgname, ID);
2099
2100 if (ID > 0) {
2101 lib_command_sprintf("# %s", fnline);
2102 record_model_command_verbatim(ID);
2103 } else {
2104 lib_command_strcpy(fnline);
2105 record_command_verbatim();
2106 if (dummy_list) {
2107 lib_command_strcpy("list " DUMLIST " delete");
2108 record_command_verbatim();
2109 }
2110 }
2111 }
2112
2113 if (cinfo->flags & MODEL_CALL) {
2114 unset_genr_model();
2115 }
2116
2117 if (!err && cinfo->rettype == GRETL_TYPE_BUNDLE) {
2118 if (grab_bundle) {
2119 bundle = get_bundle_by_name(tmpname);
2120 if (bundle != NULL && !gretl_bundle_has_content(bundle)) {
2121 /* we got a useless empty bundle */
2122 gretl_bundle_pull_from_stack(tmpname, &err);
2123 gretl_bundle_destroy(bundle);
2124 bundle = NULL;
2125 }
2126 } else if (cinfo->ret != NULL) {
2127 bundle = get_bundle_by_name(cinfo->ret);
2128 }
2129 }
2130
2131 if (!err && bundle != NULL && !show) {
2132 gretl_print_reset_buffer(prn);
2133 if (try_exec_bundle_print_function(bundle, prn)) {
2134 /* flag the fact that we do have something to show */
2135 show = 1;
2136 }
2137 }
2138
2139 if (grab_bundle && bundle != NULL) {
2140 /* If the user specified an assignment of a returned bundle,
2141 we should leave it in the user_vars stack; but if we added
2142 the assignment automatically, we should pull it out of the
2143 stack, leaving the saving (or not) up to the user.
2144 */
2145 gretl_bundle_pull_from_stack(tmpname, &err);
2146 }
2147
2148 if (!err && !show) {
2149 gretl_print_destroy(prn);
2150 } else if (outwin == NULL) {
2151 /* output window not already in place */
2152 view_buffer(prn, 80, 400, title,
2153 (bundle == NULL)? PRINT : VIEW_BUNDLE,
2154 bundle);
2155 } else {
2156 /* an output window has already been opened
2157 via "flush" */
2158 if (bundle != NULL) {
2159 finalize_script_output_window(VIEW_BUNDLE, bundle);
2160 } else {
2161 finalize_script_output_window(0, NULL);
2162 }
2163 }
2164
2165 free(tmpname);
2166
2167 if (err && !show) {
2168 gui_errmsg(err);
2169 }
2170
2171 if (check_dataset_is_changed(dataset)) {
2172 mark_dataset_as_modified();
2173 populate_varlist();
2174 }
2175
2176 return err;
2177 }
2178
2179 /* For interface selection via the GUI, when no gui-main
2180 is set: we'll suppose that if there's an interface with
2181 the same name as the package itself, it should probably
2182 be the first option on the list
2183 */
2184
maybe_reshuffle_iface_order(call_info * cinfo)2185 static void maybe_reshuffle_iface_order (call_info *cinfo)
2186 {
2187 int *list = cinfo->publist;
2188 const char *s;
2189 int i, pref = 1;
2190
2191 for (i=1; i<=list[0]; i++) {
2192 s = user_function_name_by_index(list[i]);
2193 if (!strcmp(s, cinfo->pkgname)) {
2194 pref = i;
2195 break;
2196 }
2197 }
2198
2199 if (pref > 1) {
2200 int tmp = list[1];
2201
2202 list[1] = list[pref];
2203 list[pref] = tmp;
2204 }
2205 }
2206
2207 /* In case a function package offers more than one public
2208 interface, give the user a selector: for four or fewer
2209 options we use radio buttons, otherwise we use a pull-down
2210 list.
2211 */
2212
pkg_select_interface(call_info * cinfo,int npub)2213 static void pkg_select_interface (call_info *cinfo, int npub)
2214 {
2215 const char *funname;
2216 char **opts = NULL;
2217 GList *ilist = NULL;
2218 int radios = (npub < 5);
2219 int i, nopts = 0;
2220 int err = 0;
2221
2222 maybe_reshuffle_iface_order(cinfo);
2223
2224 for (i=1; i<=npub && !err; i++) {
2225 funname = user_function_name_by_index(cinfo->publist[i]);
2226 if (funname == NULL) {
2227 err = E_DATA;
2228 } else if (radios) {
2229 err = strings_array_add(&opts, &nopts, funname);
2230 } else {
2231 ilist = g_list_append(ilist, (gpointer) funname);
2232 }
2233 }
2234
2235 if (err) {
2236 cinfo->iface = -1;
2237 gui_errmsg(err);
2238 } else {
2239 GtkWidget *parent = vwin_toplevel(cinfo->vwin);
2240 int resp;
2241
2242 if (radios) {
2243 gchar *title = g_strdup_printf("gretl: %s\n", cinfo->pkgname);
2244
2245 resp = radio_dialog(title, _("Select function"),
2246 (const char **) opts,
2247 nopts, 0, 0, parent);
2248 if (resp >= 0) {
2249 cinfo->iface = cinfo->publist[resp+1];
2250 } else {
2251 cinfo->iface = -1;
2252 }
2253 strings_array_free(opts, nopts);
2254 g_free(title);
2255 } else {
2256 resp = combo_selector_dialog(ilist, _("Select function"),
2257 0, parent);
2258 if (resp >= 0) {
2259 cinfo->iface = cinfo->publist[resp+1];
2260 } else {
2261 cinfo->iface = -1;
2262 }
2263 g_list_free(ilist);
2264 }
2265 }
2266 }
2267
2268 /* Callback from "OK" button in function call GUI: if there's a
2269 problem with the argument selection just return so the dialog stays
2270 in place and the user can correct matters; otherwise really execute
2271 the function.
2272 */
2273
fncall_exec_callback(GtkWidget * w,call_info * cinfo)2274 static void fncall_exec_callback (GtkWidget *w, call_info *cinfo)
2275 {
2276 if (check_args(cinfo)) {
2277 return;
2278 } else {
2279 PRN *prn = NULL;
2280 int autopos = -1;
2281 int err;
2282
2283 err = bufopen(&prn);
2284
2285 if (!err && cinfo->args != NULL) {
2286 err = pre_process_args(cinfo, &autopos, prn);
2287 if (err) {
2288 gui_errmsg(err);
2289 }
2290 }
2291
2292 if (!err) {
2293 err = real_GUI_function_call(cinfo, prn);
2294 } else {
2295 gretl_print_destroy(prn);
2296 }
2297
2298 if (autopos >= 0) {
2299 user_var_delete_by_name(AUTOLIST, NULL);
2300 g_free(cinfo->args[autopos]);
2301 cinfo->args[autopos] = g_strdup(SELNAME);
2302 }
2303
2304 if (cinfo->dlg != NULL && close_on_OK) {
2305 gtk_widget_destroy(cinfo->dlg);
2306 } else if (cinfo->dlg == NULL) {
2307 cinfo_free(cinfo);
2308 }
2309 }
2310 }
2311
2312 /* Here we're testing whether @pkg has a "gui-main" function
2313 that should be displayed as the default interface.
2314 */
2315
maybe_set_gui_interface(call_info * cinfo,int from_browser)2316 static void maybe_set_gui_interface (call_info *cinfo,
2317 int from_browser)
2318 {
2319 int gmid = -1, fid = -1;
2320
2321 function_package_get_properties(cinfo->pkg,
2322 "gui-main-id", &gmid,
2323 NULL);
2324
2325 if (gmid >= 0 && !from_browser) {
2326 fid = gmid;
2327 } else if (cinfo->publist[0] == 1) {
2328 /* single suitable interface: implicit gui-main */
2329 fid = cinfo->publist[1];
2330 } else if (gmid >= 0) {
2331 /* called from browser: check for masking */
2332 const ufunc *u = get_user_function_by_index(gmid);
2333
2334 if (!user_func_is_menu_only(u)) {
2335 fid = gmid;
2336 }
2337 }
2338
2339 if (fid >= 0) {
2340 /* we found a usable gui-main */
2341 gchar *name = NULL, *label = NULL;
2342
2343 cinfo->iface = fid;
2344 cinfo->flags |= SHOW_GUI_MAIN;
2345 function_package_get_properties(cinfo->pkg,
2346 "name", &name,
2347 "label", &label,
2348 NULL);
2349 if (label != NULL) {
2350 cinfo->label = label;
2351 g_free(name);
2352 } else {
2353 cinfo->label = name;
2354 }
2355 }
2356 }
2357
need_model_check(call_info * cinfo)2358 static int need_model_check (call_info *cinfo)
2359 {
2360 int i, err = 0;
2361
2362 for (i=0; i<cinfo->n_params; i++) {
2363 if (fn_param_uses_xlist(cinfo->func, i)) {
2364 if (cinfo->vwin == NULL || cinfo->vwin->role != VIEW_MODEL) {
2365 err = E_DATA;
2366 errbox(_("This function needs a model in place"));
2367 break;
2368 }
2369 }
2370 }
2371
2372 return err;
2373 }
2374
start_cinfo_for_package(const char * pkgname,const char * fname,windata_t * vwin,int * err)2375 static call_info *start_cinfo_for_package (const char *pkgname,
2376 const char *fname,
2377 windata_t *vwin,
2378 int *err)
2379 {
2380 call_info *cinfo;
2381 int data_access = 0;
2382 int gid = -1;
2383 fnpkg *pkg;
2384
2385 pkg = get_function_package_by_name(pkgname);
2386
2387 if (pkg == NULL) {
2388 /* not already loaded */
2389 pkg = get_function_package_by_filename(fname, err);
2390 if (*err) {
2391 gui_errmsg(*err);
2392 return NULL;
2393 }
2394 }
2395
2396 cinfo = cinfo_new(pkg, vwin);
2397 if (cinfo == NULL) {
2398 *err = E_ALLOC;
2399 return NULL;
2400 }
2401
2402 /* get the interface list and other basic info for package */
2403
2404 *err = function_package_get_properties(pkg,
2405 "name", &cinfo->pkgname,
2406 "version", &cinfo->pkgver,
2407 "gui-publist", &cinfo->publist,
2408 "gui-main-id", &gid,
2409 "data-requirement", &cinfo->dreq,
2410 "model-requirement", &cinfo->modelreq,
2411 "min-version", &cinfo->minver,
2412 "wants-data-access", &data_access,
2413 NULL);
2414
2415 if (*err) {
2416 gui_errmsg(*err);
2417 } else if (cinfo->publist == NULL) {
2418 if (gid >= 0) {
2419 cinfo->publist = gretl_list_new(1);
2420 cinfo->publist[1] = gid;
2421 }
2422 }
2423
2424 if (!*err && cinfo->publist == NULL) {
2425 /* no available interfaces */
2426 errbox(_("Function package is broken"));
2427 *err = E_DATA;
2428 }
2429
2430 if (!*err && data_access) {
2431 cinfo->flags |= DATA_ACCESS;
2432 }
2433
2434 if (*err) {
2435 cinfo_free(cinfo);
2436 cinfo = NULL;
2437 }
2438
2439 return cinfo;
2440 }
2441
2442 /* Call to execute a function from the package pre-attached to
2443 @cinfo. We may or may not end up offering a list of
2444 interfaces. This is called both from menu items (see below in this
2445 file) and (indirectly) from the "browser" window that lists
2446 installed function packages -- see open_function_package() below.
2447 */
2448
call_function_package(call_info * cinfo,windata_t * vwin,const char * path,int from_browser)2449 static int call_function_package (call_info *cinfo,
2450 windata_t *vwin,
2451 const char *path,
2452 int from_browser)
2453 {
2454 int err = 0;
2455
2456 if (!from_browser) {
2457 /* Do we have suitable data in place? (This is already
2458 checked if @from_browser is non-zero).
2459 */
2460 err = check_function_needs(dataset, cinfo->dreq, cinfo->minver);
2461 if (err) {
2462 gui_errmsg(err);
2463 }
2464 }
2465
2466 if (!err) {
2467 maybe_set_gui_interface(cinfo, from_browser);
2468 }
2469
2470 if (!err && cinfo->iface < 0) {
2471 pkg_select_interface(cinfo, cinfo->publist[0]);
2472 if (cinfo->iface < 0) {
2473 /* failed, or cancelled */
2474 cinfo_free(cinfo);
2475 return 0; /* note: handled */
2476 }
2477 }
2478
2479 if (!err) {
2480 cinfo->func = get_user_function_by_index(cinfo->iface);
2481 if (cinfo->func == NULL) {
2482 fprintf(stderr, "get_user_function_by_index: failed\n");
2483 errbox(_("Couldn't get function package information"));
2484 }
2485 }
2486
2487 if (!err) {
2488 cinfo->n_params = fn_n_params(cinfo->func);
2489 err = function_data_check(cinfo, vwin, path);
2490 }
2491
2492 if (!err) {
2493 cinfo->rettype = user_func_get_return_type(cinfo->func);
2494 if (err) {
2495 fprintf(stderr, "user_func_get_return_type: failed\n");
2496 errbox(_("Couldn't get function package information"));
2497 }
2498 }
2499
2500 if (!err) {
2501 /* Should this check come earlier? */
2502 err = need_model_check(cinfo);
2503 }
2504
2505 if (!err) {
2506 if (fn_n_params(cinfo->func) == 0) {
2507 /* no arguments to be gathered */
2508 fncall_exec_callback(NULL, cinfo);
2509 } else {
2510 /* put up a dialog to collect arguments */
2511 err = function_call_dialog(cinfo);
2512 }
2513 } else {
2514 cinfo_free(cinfo);
2515 }
2516
2517 return err;
2518 }
2519
maybe_open_sample_script(call_info * cinfo,windata_t * vwin,const char * path)2520 static void maybe_open_sample_script (call_info *cinfo,
2521 windata_t *vwin,
2522 const char *path)
2523 {
2524 const char *ts_msg = N_("This package needs time series data.");
2525 const char *qm_msg = N_("This package needs quarterly or monthly data.");
2526 const char *pn_msg = N_("This package needs panel data.");
2527 const char *ds_msg = N_("This package needs a dataset in place.");
2528 const char *query = N_("Would you like to open its sample script?");
2529 gchar *msg, *title = cinfo_pkg_title(cinfo);
2530 const char *req;
2531 int resp;
2532
2533 if (cinfo->dreq == FN_NEEDS_TS) {
2534 req = ts_msg;
2535 } else if (cinfo->dreq == FN_NEEDS_QM) {
2536 req = qm_msg;
2537 } else if (cinfo->dreq == FN_NEEDS_PANEL) {
2538 req = pn_msg;
2539 } else {
2540 req = ds_msg;
2541 }
2542
2543 msg = g_strdup_printf("%s\n%s", _(req), _(query));
2544 resp = yes_no_dialog(title, msg, vwin_toplevel(vwin));
2545
2546 if (resp == GRETL_YES) {
2547 display_function_package_data(cinfo->pkgname, path,
2548 VIEW_PKG_SAMPLE);
2549 }
2550
2551 g_free(msg);
2552 }
2553
2554 /* Called from the function-package browser: unless the
2555 package can't be loaded we should return 0 to signal
2556 that loading happened.
2557 */
2558
open_function_package(const char * pkgname,const char * fname,windata_t * vwin)2559 int open_function_package (const char *pkgname,
2560 const char *fname,
2561 windata_t *vwin)
2562 {
2563 call_info *cinfo;
2564 int can_call = 1;
2565 int free_cinfo = 1;
2566 int err = 0;
2567
2568 /* note: this ensures the package gets loaded */
2569 cinfo = start_cinfo_for_package(pkgname, fname, vwin, &err);
2570
2571 if (err) {
2572 return err;
2573 }
2574
2575 /* do we have suitable data in place? */
2576 err = check_function_needs(dataset, cinfo->dreq, cinfo->minver);
2577
2578 if (err == E_DATA) {
2579 /* we might still run the sample script */
2580 can_call = 0;
2581 err = 0;
2582 gretl_error_clear();
2583 } else if (err) {
2584 /* fatal error */
2585 gui_errmsg(err);
2586 return err;
2587 }
2588
2589 if (can_call) {
2590 /* actually call the package: must preserve @cinfo! */
2591 free_cinfo = 0;
2592 call_function_package(cinfo, vwin, fname, 1);
2593 } else {
2594 /* notify and give choice of running sample */
2595 maybe_open_sample_script(cinfo, vwin, fname);
2596 }
2597
2598 if (free_cinfo) {
2599 cinfo_free(cinfo);
2600 }
2601
2602 return 0;
2603 }
2604
function_call_cleanup(void)2605 void function_call_cleanup (void)
2606 {
2607 if (open_fncall_dlg != NULL) {
2608 gtk_widget_destroy(open_fncall_dlg);
2609 }
2610
2611 arglist_cleanup();
2612 }
2613
compose_pkg_title(ufunc * func,const char * id)2614 static gchar *compose_pkg_title (ufunc *func,
2615 const char *id)
2616 {
2617 fnpkg *pkg = gretl_function_get_package(func);
2618 const char *pname = function_package_get_name(pkg);
2619 gchar *title;
2620
2621 if (!strcmp(id, BUNDLE_FCAST)) {
2622 title = g_strdup_printf("gretl: %s %s", pname, _("forecast"));
2623 } else {
2624 title = g_strdup_printf("gretl: %s bundle", pname);
2625 }
2626
2627 return title;
2628 }
2629
2630 /* Execute a special-purpose function made available by the
2631 package that produced bundle @b, possibly inflected by an
2632 integer option. If an option is present it's packed into
2633 @aname, following a colon.
2634 */
2635
exec_bundle_special_function(gretl_bundle * b,const char * id,const char * aname,GtkWidget * parent)2636 int exec_bundle_special_function (gretl_bundle *b,
2637 const char *id,
2638 const char *aname,
2639 GtkWidget *parent)
2640 {
2641 ufunc *func = NULL;
2642 fncall *fc = NULL;
2643 char funname[32];
2644 PRN *prn = NULL;
2645 int plotting = 0;
2646 int forecast = 0;
2647 int t1 = 0, t2 = 0;
2648 int iopt = -1;
2649 int err = 0;
2650
2651 plotting = strcmp(id, BUNDLE_PLOT) == 0;
2652 forecast = strcmp(id, BUNDLE_FCAST) == 0;
2653
2654 if (aname != NULL) {
2655 if (strchr(aname, ':') != NULL) {
2656 /* extract option */
2657 sscanf(aname, "%31[^:]:%d", funname, &iopt);
2658 } else {
2659 /* name but no option present */
2660 strcpy(funname, aname);
2661 }
2662 } else {
2663 gchar *sf = get_bundle_special_function(b, id);
2664
2665 if (sf == NULL) {
2666 return E_DATA;
2667 } else {
2668 strcpy(funname, sf);
2669 g_free(sf);
2670 }
2671 }
2672
2673 func = get_user_function_by_name(funname);
2674
2675 if (func == NULL) {
2676 errbox_printf(_("Couldn't find function %s"), funname);
2677 return E_DATA;
2678 }
2679
2680 if (forecast) {
2681 /* check for feasibility */
2682 int resp = simple_forecast_dialog(&t1, &t2, parent);
2683
2684 if (canceled(resp)) {
2685 return 0;
2686 }
2687 allow_full_data_access(1);
2688 }
2689
2690 if (!err) {
2691 user_var *uv = get_user_var_by_data(b);
2692 const char *bname = NULL;
2693
2694 if (uv != NULL) {
2695 bname = user_var_get_name(uv);
2696 }
2697 fc = fncall_new(func, 0);
2698 if (bname != NULL) {
2699 err = push_function_arg(fc, bname, uv, GRETL_TYPE_BUNDLE_REF, b);
2700 } else {
2701 err = push_anon_function_arg(fc, GRETL_TYPE_BUNDLE_REF, b);
2702 }
2703 if (!err && forecast) {
2704 t1++; t2++; /* convert to 1-based */
2705 push_anon_function_arg(fc, GRETL_TYPE_INT, &t1);
2706 push_anon_function_arg(fc, GRETL_TYPE_INT, &t2);
2707 } else if (!err && iopt >= 0) {
2708 /* add the option flag, if any, to args */
2709 double minv = fn_param_minval(func, 1);
2710
2711 if (!na(minv)) {
2712 iopt += (int) minv;
2713 err = push_anon_function_arg(fc, GRETL_TYPE_INT, &iopt);
2714 }
2715 }
2716 }
2717
2718 if (!err) {
2719 if (plotting) {
2720 prn = gretl_print_new(GRETL_PRINT_STDERR, &err);
2721 } else {
2722 err = bufopen(&prn);
2723 }
2724 }
2725
2726 if (!err && plotting) {
2727 /* A plotting function may need a non-NULL PRN for
2728 use with printing redirection (outfile). But we
2729 don't expect any printed output.
2730 */
2731 err = gretl_function_exec(fc, GRETL_TYPE_NONE, dataset,
2732 NULL, NULL, prn);
2733 } else if (!err) {
2734 /* For other bundle-specials we expect printed output */
2735 GretlType rtype = user_func_get_return_type(func);
2736 gretl_bundle *retb = NULL;
2737
2738 if (rtype == GRETL_TYPE_BUNDLE) {
2739 /* if a bundle is offered, let's grab it */
2740 err = gretl_function_exec(fc, GRETL_TYPE_BUNDLE, dataset,
2741 &retb, NULL, prn);
2742 } else {
2743 /* otherwise ignore any return value */
2744 err = gretl_function_exec(fc, GRETL_TYPE_NONE, dataset,
2745 NULL, NULL, prn);
2746 }
2747 if (err) {
2748 gui_errmsg(err);
2749 } else {
2750 int role = retb != NULL ? VIEW_BUNDLE : PRINT;
2751 gchar *title = compose_pkg_title(func, id);
2752
2753 view_buffer(prn, 78, 450, title, role, retb);
2754 g_free(title);
2755 prn = NULL; /* ownership taken by viewer */
2756 }
2757 } else {
2758 fncall_destroy(fc);
2759 }
2760
2761 gretl_print_destroy(prn);
2762
2763 if (err) {
2764 gui_errmsg(err);
2765 }
2766
2767 return err;
2768 }
2769
2770 /* See if a bundle has the name of a "creator" function package
2771 recorded on it. If so, see whether that package is already loaded,
2772 or can be loaded. And if that works, see if the package has a
2773 default function for @task (e.g. BUNDLE_PRINT).
2774 */
2775
get_bundle_special_function(gretl_bundle * b,const char * id)2776 gchar *get_bundle_special_function (gretl_bundle *b,
2777 const char *id)
2778 {
2779 const char *pkgname = gretl_bundle_get_creator(b);
2780 gchar *ret = NULL;
2781
2782 if (pkgname != NULL && *pkgname != '\0') {
2783 fnpkg *pkg = get_function_package_by_name(pkgname);
2784
2785 if (pkg == NULL) {
2786 char *fname =
2787 gretl_function_package_get_path(pkgname, PKG_ALL);
2788 int err = 0;
2789
2790 if (fname != NULL) {
2791 pkg = get_function_package_by_filename(fname, &err);
2792 free(fname);
2793 }
2794 }
2795 if (pkg != NULL) {
2796 function_package_get_properties(pkg, id, &ret, NULL);
2797 }
2798 }
2799
2800 return ret;
2801 }
2802
2803 /* See if we can find a "native" printing function for a
2804 gretl bundle. If we can find this, try executing it.
2805
2806 Notice that this function returns 1 on success, 0 on
2807 failure.
2808 */
2809
try_exec_bundle_print_function(gretl_bundle * b,PRN * prn)2810 int try_exec_bundle_print_function (gretl_bundle *b, PRN *prn)
2811 {
2812 gchar *funname;
2813 int ret = 0;
2814
2815 funname = get_bundle_special_function(b, BUNDLE_PRINT);
2816
2817 if (funname != NULL) {
2818 const char *name = user_var_get_name_by_data(b);
2819 gchar *genline;
2820 int err;
2821
2822 genline = g_strdup_printf("%s(&%s)", funname, name);
2823 err = generate_void(genline, dataset, prn);
2824 g_free(genline);
2825 if (err) {
2826 gui_errmsg(err);
2827 } else {
2828 ret = 1;
2829 }
2830 }
2831
2832 return ret;
2833 }
2834
2835 /* get a listing of available "official" addons along with (a) the
2836 name of the versioned subdirectory containing the most recent
2837 usable version (given the gretl version) and (b) the date of that
2838 package version, taken from its spec file. E.g.
2839
2840 gig 1.9.5 2011-04-22
2841 ivpanel 1.9.4 2011-02-10
2842 */
2843
query_addons(void)2844 int query_addons (void)
2845 {
2846 gchar *query;
2847 char *buf = NULL;
2848 int err = 0;
2849
2850 query = g_strdup_printf("/addons-data/pkginfo.php?gretl_version=%s",
2851 GRETL_VERSION);
2852 err = query_sourceforge(query, &buf);
2853 g_free(query);
2854
2855 if (!err && buf == NULL) {
2856 /* shouldn't happen */
2857 err = E_DATA;
2858 }
2859
2860 if (!err) {
2861 infobox(buf);
2862 }
2863
2864 free(buf);
2865
2866 return err;
2867 }
2868
download_addon(const char * pkgname,char ** local_path)2869 int download_addon (const char *pkgname, char **local_path)
2870 {
2871 char *uri;
2872 int err = 0;
2873
2874 uri = get_uri_for_addon(pkgname, &err);
2875
2876 if (!err) {
2877 const char *path = gretl_function_package_path();
2878 gchar *fullname = g_strdup_printf("%s%s.zip", path, pkgname);
2879
2880 #if 1
2881 fprintf(stderr, "download_addon: uri = '%s'\n", uri);
2882 fprintf(stderr, "download_addon: fname = '%s'\n", fullname);
2883 #endif
2884
2885 err = retrieve_public_file(uri, fullname);
2886 fprintf(stderr, "retrieve_public_file: err = %d\n", err);
2887 if (!err) {
2888 err = gretl_unzip_into(fullname, path);
2889 fprintf(stderr, "gretl_unzip_into: err = %d\n", err);
2890 gretl_remove(fullname);
2891 }
2892 if (err) {
2893 gui_errmsg(err);
2894 } else {
2895 update_addons_index(NULL);
2896 if (local_path != NULL) {
2897 /* fill local path to gfn file */
2898 gchar *tmp;
2899
2900 tmp = g_build_filename(path, pkgname, pkgname, NULL);
2901 *local_path = calloc(strlen(tmp) + 5, 1);
2902 sprintf(*local_path, "%s.gfn", tmp);
2903 g_free(tmp);
2904 fprintf(stderr, "local_path: '%s'\n", *local_path);
2905 }
2906 }
2907 g_free(fullname);
2908 }
2909
2910 free(uri);
2911
2912 return err;
2913 }
2914
2915 /* information about a function package that offers a
2916 menu attachment point */
2917
2918 typedef enum {
2919 GPI_MODELWIN = 1 << 0,
2920 GPI_SUBDIR = 1 << 1,
2921 GPI_SYSFILE = 1 << 2,
2922 GPI_INCLUDED = 1 << 3,
2923 GPI_DATAREQ = 1 << 4
2924 } GpiFlags;
2925
2926 enum {
2927 SYS_PACKAGES,
2928 USER_PACKAGES
2929 };
2930
2931 #define gpi_included(g) (g->flags & GPI_INCLUDED)
2932 #define gpi_modelwin(g) (g->flags & GPI_MODELWIN)
2933 #define gpi_sysfile(g) (g->flags & GPI_SYSFILE)
2934 #define gpi_subdir(g) (g->flags & GPI_SUBDIR)
2935 #define gpi_ptype(g) ((g->flags & GPI_SUBDIR)? PKG_SUBDIR : PKG_TOPLEV)
2936
2937 struct gui_package_info_ {
2938 char *pkgname; /* @name element from packages.xml */
2939 char *label; /* @label element from packages.xml */
2940 char *menupath; /* @path element from packages.xml */
2941 char *filepath; /* actual filesystem path */
2942 DataReq dreq; /* data requirement */
2943 int modelreq; /* model (command number) requirement */
2944 GpiFlags flags; /* state flags */
2945 guint merge_id; /* created at runtime when added to GUI */
2946 GtkActionGroup *ag; /* run-time UI thing */
2947 };
2948
2949 typedef struct gui_package_info_ gui_package_info;
2950
2951 static void add_package_to_menu (gui_package_info *gpi,
2952 windata_t *vwin);
2953
2954 static gui_package_info *gpkgs;
2955 static int n_gpkgs;
2956 static int gpkgs_changed;
2957
2958 /* Return the total number of slots for function packages
2959 "registered" for use via menus. Note that this number
2960 may include some slots that are actually empty, if the
2961 user has removed a dynamic menu item during the
2962 current gretl session.
2963 */
2964
n_registered_packages(void)2965 int n_registered_packages (void)
2966 {
2967 return n_gpkgs;
2968 }
2969
n_user_handled_packages(void)2970 int n_user_handled_packages (void)
2971 {
2972 int i, n = 0;
2973
2974 for (i=0; i<n_gpkgs; i++) {
2975 if (gpkgs[i].pkgname == NULL) {
2976 /* a vacant slot */
2977 continue;
2978 } else if (gpkgs[i].flags & GPI_SYSFILE) {
2979 /* a file under control of the "system"
2980 packages.xml file */
2981 continue;
2982 } else {
2983 n++;
2984 }
2985 }
2986
2987 return n;
2988 }
2989
2990 /* On adding a new entry to the gui package info
2991 array, zero it appropriately */
2992
gpi_entry_init(gui_package_info * gpi)2993 static void gpi_entry_init (gui_package_info *gpi)
2994 {
2995 gpi->pkgname = NULL;
2996 gpi->label = NULL;
2997 gpi->menupath = NULL;
2998 gpi->filepath = NULL;
2999 gpi->dreq = FN_NEEDS_DATA;
3000 gpi->modelreq = 0;
3001 gpi->flags = 0;
3002 gpi->merge_id = 0;
3003 gpi->ag = NULL;
3004 }
3005
packages_xml_path(int which)3006 static gchar *packages_xml_path (int which)
3007 {
3008 if (which == SYS_PACKAGES) {
3009 return g_strdup_printf("%sfunctions%cpackages.xml",
3010 gretl_home(), SLASH);
3011 } else {
3012 return g_strdup_printf("%sfunctions%cpackages.xml",
3013 gretl_dotdir(), SLASH);
3014 }
3015 }
3016
modelreq_string(int ci)3017 static const char *modelreq_string (int ci)
3018 {
3019 if (ci == 0) {
3020 return "any";
3021 } else {
3022 return gretl_command_word(ci);
3023 }
3024 }
3025
write_packages_xml(void)3026 static void write_packages_xml (void)
3027 {
3028 gchar *fname = packages_xml_path(USER_PACKAGES);
3029 int i, n_write = n_user_handled_packages();
3030
3031 if (n_write == 0) {
3032 gretl_remove(fname);
3033 } else {
3034 FILE *fp = gretl_fopen(fname, "w");
3035
3036 if (fp == NULL) {
3037 fprintf(stderr, "Couldn't write to %s\n", fname);
3038 return;
3039 }
3040
3041 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp);
3042 fputs("<gretl-package-info>\n", fp);
3043
3044 for (i=0; i<n_gpkgs; i++) {
3045 if (gpkgs[i].pkgname != NULL &&
3046 !(gpkgs[i].flags & GPI_SYSFILE)) {
3047 fprintf(fp, "<package name=\"%s\"", gpkgs[i].pkgname);
3048 fprintf(fp, " label=\"%s\"", gpkgs[i].label);
3049 if (gpkgs[i].flags & GPI_MODELWIN) {
3050 fputs(" model-window=\"true\"", fp);
3051 fprintf(fp, " model-requirement=\"%s\"",
3052 modelreq_string(gpkgs[i].modelreq));
3053 }
3054 fprintf(fp, " path=\"%s\"", gpkgs[i].menupath);
3055 if (!(gpkgs[i].flags & GPI_SUBDIR)) {
3056 fputs(" toplev=\"true\"", fp);
3057 }
3058 if (gpkgs[i].flags & GPI_DATAREQ) {
3059 fprintf(fp, " data-requirement=\"%d\"", gpkgs[i].dreq);
3060 }
3061 fputs("/>\n", fp);
3062 }
3063 }
3064
3065 fputs("</gretl-package-info>\n", fp);
3066 fclose(fp);
3067 }
3068
3069 g_free(fname);
3070 }
3071
3072 /* At exit, clean up the entire array of gui package
3073 info, after first saving the info to file if anything
3074 relevant has changed.
3075 */
3076
destroy_gui_package_info(void)3077 void destroy_gui_package_info (void)
3078 {
3079 if (gpkgs_changed) {
3080 /* save info to packages.xml first */
3081 write_packages_xml();
3082 }
3083
3084 if (gpkgs != NULL && n_gpkgs > 0) {
3085 int i;
3086
3087 for (i=0; i<n_gpkgs; i++) {
3088 free(gpkgs[i].pkgname);
3089 free(gpkgs[i].label);
3090 free(gpkgs[i].menupath);
3091 free(gpkgs[i].filepath);
3092 }
3093 free(gpkgs);
3094 }
3095
3096 gpkgs = NULL;
3097 n_gpkgs = 0;
3098 gpkgs_changed = 0;
3099 }
3100
gpkg_name_match(char * s1,const char * s2)3101 static int gpkg_name_match (char *s1, const char *s2)
3102 {
3103 return s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0;
3104 }
3105
get_gpi_entry(const gchar * pkgname)3106 static gui_package_info *get_gpi_entry (const gchar *pkgname)
3107 {
3108 int i;
3109
3110 for (i=0; i<n_gpkgs; i++) {
3111 if (gpkg_name_match(gpkgs[i].pkgname, pkgname)) {
3112 return &gpkgs[i];
3113 }
3114 }
3115
3116 return NULL;
3117 }
3118
get_registered_pkg_info(int i,char ** name,char ** path,char ** label,int * modelwin)3119 void get_registered_pkg_info (int i, char **name, char **path,
3120 char **label, int *modelwin)
3121 {
3122 if (i < 0 || i >= n_gpkgs ||
3123 gpkgs[i].pkgname == NULL ||
3124 (gpkgs[i].flags & GPI_SYSFILE)) {
3125 *name = *path = *label = NULL;
3126 } else {
3127 *name = gpkgs[i].pkgname;
3128 *path = gpkgs[i].menupath;
3129 *label = gpkgs[i].label;
3130 *modelwin = (gpkgs[i].flags & GPI_MODELWIN)? 1 : 0;
3131 }
3132 }
3133
maybe_record_include(const char * pkgname,int model_id)3134 static void maybe_record_include (const char *pkgname,
3135 int model_id)
3136 {
3137 gui_package_info *gpi;
3138 int i;
3139
3140 for (i=0; i<n_gpkgs; i++) {
3141 gpi = &gpkgs[i];
3142 if (gpkg_name_match(gpi->pkgname, pkgname)) {
3143 if (!gpi_included(gpi)) {
3144 lib_command_sprintf("include %s.gfn", pkgname);
3145 if (model_id > 0) {
3146 record_model_command_verbatim(model_id);
3147 } else {
3148 record_command_verbatim();
3149 }
3150 gpi->flags |= GPI_INCLUDED;
3151 }
3152 break;
3153 }
3154 }
3155 }
3156
package_is_available_for_menu(const gchar * pkgname,const char * fname)3157 int package_is_available_for_menu (const gchar *pkgname,
3158 const char *fname)
3159 {
3160 int present = 0;
3161 int i, ret = 0;
3162
3163 for (i=0; i<n_gpkgs && !present; i++) {
3164 if (gpkg_name_match(gpkgs[i].pkgname, pkgname)) {
3165 present = 1;
3166 }
3167 }
3168
3169 if (!present) {
3170 /* not already present in menus: can it be added? */
3171 ret = package_has_menu_attachment(fname, NULL, NULL, NULL);
3172 }
3173
3174 return ret;
3175 }
3176
3177 /* Callback for a menu item representing a function package whose
3178 name is attached to @action. We first see if we can find the full
3179 path to the corresponding gfn file; if so we initiate a GUI call to
3180 the package.
3181 */
3182
gfn_menu_callback(GtkAction * action,windata_t * vwin)3183 static void gfn_menu_callback (GtkAction *action, windata_t *vwin)
3184 {
3185 const gchar *pkgname = gtk_action_get_name(action);
3186 gui_package_info *gpi;
3187
3188 gpi = get_gpi_entry(pkgname);
3189 if (gpi == NULL) {
3190 /* "can't happen" */
3191 return;
3192 }
3193
3194 if (gpi->filepath == NULL) {
3195 gpi->filepath =
3196 gretl_function_package_get_path(pkgname, gpi_ptype(gpi));
3197 }
3198
3199 if (gpi->filepath == NULL && is_gretl_addon(pkgname)) {
3200 gchar *msg = g_strdup_printf(_("The %s package was not found, or is not "
3201 "up to date.\nWould you like to try "
3202 "downloading it now?"), pkgname);
3203 int resp = yes_no_dialog(NULL, msg, vwin_toplevel(vwin));
3204
3205 g_free(msg);
3206 if (resp == GRETL_YES) {
3207 int err = download_addon(pkgname, &gpi->filepath);
3208
3209 if (err) {
3210 return;
3211 }
3212 } else {
3213 /* canceled, effectively */
3214 return;
3215 }
3216 }
3217
3218 if (gpi->filepath != NULL) {
3219 call_info *cinfo;
3220 int err = 0;
3221
3222 cinfo = start_cinfo_for_package(pkgname, gpi->filepath, vwin, &err);
3223 if (cinfo != NULL) {
3224 call_function_package(cinfo, vwin, gpi->filepath, 0);
3225 }
3226 } else {
3227 errbox_printf("Sorry, could not find %s", pkgname);
3228 gui_function_pkg_unregister(pkgname);
3229 }
3230 }
3231
package_is_unseen(const char * name,int n)3232 static int package_is_unseen (const char *name, int n)
3233 {
3234 int i;
3235
3236 for (i=0; i<n; i++) {
3237 if (gpkg_name_match(gpkgs[i].pkgname, name)) {
3238 return 0;
3239 }
3240 }
3241
3242 return 1;
3243 }
3244
gpi_set_flags(gui_package_info * gpi,int which,int subdir,int modelwin,int need_dreq)3245 static void gpi_set_flags (gui_package_info *gpi,
3246 int which,
3247 int subdir,
3248 int modelwin,
3249 int need_dreq)
3250 {
3251 gpi->flags = 0;
3252
3253 if (which == SYS_PACKAGES) {
3254 gpi->flags |= GPI_SYSFILE;
3255 }
3256 if (subdir) {
3257 gpi->flags |= GPI_SUBDIR;
3258 }
3259 if (modelwin) {
3260 gpi->flags |= GPI_MODELWIN;
3261 }
3262 if (need_dreq) {
3263 gpi->flags |= GPI_DATAREQ;
3264 }
3265 }
3266
3267 /* Use libxml2 to peek inside package and determine its data
3268 or model requirement, without having to load the package
3269 into memory.
3270 */
3271
gfn_peek_requirement(const char * fname,int model)3272 static int gfn_peek_requirement (const char *fname, int model)
3273 {
3274 int ret = 0;
3275 xmlDocPtr doc = NULL;
3276 xmlNodePtr node = NULL;
3277 xmlNodePtr cur;
3278 int err;
3279
3280 err = gretl_xml_open_doc_root(fname, "gretl-functions", &doc, &node);
3281
3282 if (!err) {
3283 cur = node->xmlChildrenNode;
3284 while (cur != NULL) {
3285 if (!xmlStrcmp(cur->name, (XUC) "gretl-function-package")) {
3286 if (model) {
3287 char *s = NULL;
3288
3289 gretl_xml_get_prop_as_string(cur, "model-requirement", &s);
3290 if (s != NULL) {
3291 ret = gretl_command_number(s);
3292 free(s);
3293 }
3294 break;
3295 }
3296 if (gretl_xml_get_prop_as_bool(cur, NEEDS_TS)) {
3297 ret = FN_NEEDS_TS;
3298 } else if (gretl_xml_get_prop_as_bool(cur, NEEDS_QM)) {
3299 ret = FN_NEEDS_QM;
3300 } else if (gretl_xml_get_prop_as_bool(cur, NEEDS_PANEL)) {
3301 ret = FN_NEEDS_PANEL;
3302 } else if (gretl_xml_get_prop_as_bool(cur, NO_DATA_OK)) {
3303 ret = FN_NODATA_OK;
3304 }
3305 break;
3306 }
3307 cur = cur->next;
3308 }
3309 }
3310
3311 if (doc != NULL) {
3312 xmlFreeDoc(doc);
3313 }
3314
3315 return ret;
3316 }
3317
discover_gfn_requirement(const char * pkgname,int toplev,int model)3318 static int discover_gfn_requirement (const char *pkgname,
3319 int toplev, int model)
3320 {
3321 char *path;
3322 PkgType ptype;
3323 int ret = 0;
3324
3325 ptype = toplev ? PKG_TOPLEV : PKG_SUBDIR;
3326 path = gretl_function_package_get_path(pkgname, ptype);
3327 if (path != NULL) {
3328 ret = gfn_peek_requirement(path, model);
3329 free(path);
3330 }
3331
3332 return ret;
3333 }
3334
3335 /* Figure out whether we need to pay attention to the data requirement
3336 of a function package in order to set its sensitivity ("grayed out"
3337 or not). We don't need to do this if it has a model-window
3338 attachment (the package will be added to a model-window menu only
3339 if its model-type specification is matched). Neither do we need
3340 this if the package attaches under the main-window Model menu: in
3341 that case its sensitivity will be governed by the code that sets
3342 the overall sensitivity of the Model menu and its sub-menus
3343 (time-series, panel).
3344 */
3345
need_gfn_data_req(const char * path)3346 static int need_gfn_data_req (const char *path)
3347 {
3348 return strncmp(path, "/menubar/Model", 14) != 0;
3349 }
3350
read_packages_file(const char * fname,int * pn,int which)3351 static int read_packages_file (const char *fname, int *pn, int which)
3352 {
3353 xmlDocPtr doc = NULL;
3354 xmlNodePtr cur = NULL;
3355 int err, n = *pn;
3356
3357 err = gretl_xml_open_doc_root(fname, "gretl-package-info", &doc, &cur);
3358 if (err) {
3359 return (which == SYS_PACKAGES)? err : 0;
3360 }
3361
3362 cur = cur->xmlChildrenNode;
3363
3364 while (cur != NULL && !err) {
3365 if (!xmlStrcmp(cur->name, (XUC) "package")) {
3366 int mw = gretl_xml_get_prop_as_bool(cur, "model-window");
3367 int top = gretl_xml_get_prop_as_bool(cur, "toplev");
3368 char *name, *desc, *path;
3369 int dreq, modelreq = 0, need_dr = 0;
3370 int freeit = 1;
3371
3372 name = (char *) xmlGetProp(cur, (XUC) "name");
3373 desc = (char *) xmlGetProp(cur, (XUC) "label");
3374 path = (char *) xmlGetProp(cur, (XUC) "path");
3375 if (name == NULL || desc == NULL || path == NULL) {
3376 err = E_DATA;
3377 break;
3378 }
3379
3380 if (!strcmp(name, "SVAR") &&
3381 !strcmp(path, "/menubar/Model/TSModels")) {
3382 /* update menu path (legacy SVAR) */
3383 free(path);
3384 path = gretl_strdup("/menubar/Model/TSMulti");
3385 } else if (strstr(path, "TSModels/TSMulti") ||
3386 strstr(path, "TSModels/CointMenu")) {
3387 free(path);
3388 path = gretl_strdup("/menubar/Model/TSMulti");
3389 }
3390
3391 if (mw) {
3392 /* package with a model-window attachment */
3393 if (!gretl_xml_get_prop_as_int(cur, "model-requirement", &modelreq)) {
3394 modelreq = discover_gfn_requirement(name, top, 1);
3395 gpkgs_changed = 1;
3396 }
3397 } else {
3398 /* a main-window package */
3399 need_dr = need_gfn_data_req(path);
3400 }
3401
3402 if (need_dr && !gretl_xml_get_prop_as_int(cur, "data-requirement", &dreq)) {
3403 dreq = discover_gfn_requirement(name, top, 0);
3404 gpkgs_changed = 1;
3405 }
3406
3407 if (package_is_unseen(name, n)) {
3408 gpkgs = myrealloc(gpkgs, (n+1) * sizeof *gpkgs);
3409 if (gpkgs == NULL) {
3410 err = E_ALLOC;
3411 } else {
3412 freeit = 0;
3413 gpkgs[n].pkgname = name;
3414 gpkgs[n].label = desc;
3415 gpkgs[n].menupath = path;
3416 gpkgs[n].filepath = NULL;
3417 gpi_set_flags(&gpkgs[n], which, !top, mw, need_dr);
3418 gpkgs[n].dreq = (DataReq) dreq;
3419 if (mw) {
3420 gpkgs[n].modelreq = modelreq;
3421 }
3422 gpkgs[n].merge_id = 0;
3423 gpkgs[n].ag = NULL;
3424 n++;
3425 }
3426 }
3427 if (freeit) {
3428 free(name);
3429 free(desc);
3430 free(path);
3431 }
3432 }
3433 if (!err) {
3434 cur = cur->next;
3435 }
3436 }
3437
3438 if (doc != NULL) {
3439 xmlFreeDoc(doc);
3440 }
3441
3442 *pn = n;
3443
3444 return err;
3445 }
3446
destroy_gpi_ui(gui_package_info * gpi)3447 static void destroy_gpi_ui (gui_package_info *gpi)
3448 {
3449 fprintf(stderr, "removing UI for %s\n", gpi->pkgname);
3450 gtk_ui_manager_remove_ui(mdata->ui, gpi->merge_id);
3451 gtk_ui_manager_remove_action_group(mdata->ui, gpi->ag);
3452 g_object_unref(gpi->ag);
3453
3454 gpi->merge_id = 0;
3455 gpi->ag = NULL;
3456 }
3457
3458 /* On the call to remove a dynamic menu item, tear down
3459 its UI and blank out @gpi so that it may be safely
3460 reused by another package.
3461 */
3462
clear_gpi_entry(gui_package_info * gpi)3463 static void clear_gpi_entry (gui_package_info *gpi)
3464 {
3465 if (gpi->merge_id > 0) {
3466 destroy_gpi_ui(gpi);
3467 }
3468
3469 free(gpi->pkgname);
3470 free(gpi->label);
3471 free(gpi->menupath);
3472 free(gpi->filepath);
3473
3474 gpi->pkgname = NULL;
3475 gpi->label = NULL;
3476 gpi->menupath = NULL;
3477 gpi->filepath = NULL;
3478
3479 gpi->dreq = FN_NEEDS_DATA;
3480 gpi->modelreq = 0;
3481 gpi->flags = 0;
3482
3483 gpkgs_changed = 1;
3484 }
3485
fill_gpi_entry(gui_package_info * gpi,const char * pkgname,const char * fname,const char * label,const char * relpath,int modelwin,int uses_subdir,DataReq dreq,int modelreq,int replace)3486 static int fill_gpi_entry (gui_package_info *gpi,
3487 const char *pkgname,
3488 const char *fname,
3489 const char *label,
3490 const char *relpath,
3491 int modelwin,
3492 int uses_subdir,
3493 DataReq dreq,
3494 int modelreq,
3495 int replace)
3496 {
3497 int need_dr = 0;
3498 int err = 0;
3499
3500 if (replace) {
3501 free(gpi->pkgname);
3502 free(gpi->label);
3503 free(gpi->menupath);
3504 free(gpi->filepath);
3505 }
3506
3507 gpi->pkgname = gretl_strdup(pkgname);
3508 gpi->label = gretl_strdup(label);
3509 gpi->menupath = malloc(9 + strlen(relpath));
3510 if (gpi->menupath != NULL) {
3511 sprintf(gpi->menupath, "/menubar%s", relpath);
3512 }
3513 gpi->filepath = gretl_strdup(fname);
3514 if (modelwin) {
3515 gpi->modelreq = modelreq;
3516 } else {
3517 need_dr = need_gfn_data_req(gpi->menupath);
3518 }
3519 gpi_set_flags(gpi, USER_PACKAGES, uses_subdir, modelwin, need_dr);
3520 gpi->dreq = dreq;
3521
3522 if (gpi->pkgname == NULL || gpi->label == NULL ||
3523 gpi->menupath == NULL || gpi->filepath == NULL) {
3524 err = E_ALLOC;
3525 }
3526
3527 return err;
3528 }
3529
get_new_package_info(int * err)3530 static gui_package_info *get_new_package_info (int *err)
3531 {
3532 int i, pos = -1;
3533
3534 for (i=0; i<n_gpkgs; i++) {
3535 if (gpkgs[i].pkgname == NULL) {
3536 /* found an unused slot */
3537 pos = i;
3538 break;
3539 }
3540 }
3541
3542 if (pos < 0) {
3543 /* we need to extend the array */
3544 gui_package_info *gpkgs_new;
3545 int n = n_gpkgs + 1;
3546
3547 gpkgs_new = realloc(gpkgs, n * sizeof *gpkgs);
3548 if (gpkgs_new == NULL) {
3549 *err = E_ALLOC;
3550 return NULL;
3551 } else {
3552 gpkgs = gpkgs_new;
3553 n_gpkgs = n;
3554 pos = n - 1;
3555 gpi_entry_init(&gpkgs[pos]);
3556 }
3557 }
3558
3559 return &gpkgs[pos];
3560 }
3561
menu_paths_differ(const char * rp,const char * mp)3562 static int menu_paths_differ (const char *rp, const char *mp)
3563 {
3564 if ((rp == NULL && mp != NULL) ||
3565 (rp != NULL && mp == NULL)) {
3566 return 1;
3567 } else if (rp == NULL && mp == NULL) {
3568 return 0;
3569 } else {
3570 if (!strncmp(mp, "/menubar", 8)) {
3571 mp += 8;
3572 }
3573
3574 return strcmp(rp, mp);
3575 }
3576 }
3577
gpi_strings_differ(const char * s1,const char * s2)3578 static int gpi_strings_differ (const char *s1, const char *s2)
3579 {
3580 if ((s1 == NULL && s2 != NULL) ||
3581 (s1 != NULL && s2 == NULL)) {
3582 return 1;
3583 } else if (s1 == NULL && s2 == NULL) {
3584 return 0;
3585 } else {
3586 return strcmp(s1, s2);
3587 }
3588 }
3589
3590 /* This is called when creating a new entry in the
3591 gui package registry, and also when updating
3592 the entry for a previously registered package.
3593 */
3594
update_gui_package_info(const char * pkgname,const char * fname,const char * label,const char * relpath,int modelwin,int uses_subdir,DataReq dreq,int modelreq)3595 static int update_gui_package_info (const char *pkgname,
3596 const char *fname,
3597 const char *label,
3598 const char *relpath,
3599 int modelwin,
3600 int uses_subdir,
3601 DataReq dreq,
3602 int modelreq)
3603 {
3604 gui_package_info *gpi;
3605 int menu_update = 0;
3606 int update = 0;
3607 int replace = 1;
3608 int err = 0;
3609
3610 gpi = get_gpi_entry(pkgname);
3611
3612 if (gpi != NULL) {
3613 /* found a pre-existing entry for @pkgname:
3614 let's see if there are really any changes
3615 */
3616 if (gpi_strings_differ(label, gpi->label)) {
3617 menu_update = update = 1;
3618 } else if (menu_paths_differ(relpath, gpi->menupath)) {
3619 menu_update = update = 1;
3620 } else if (gpi_strings_differ(fname, gpi->filepath)) {
3621 update = 1;
3622 } else if (modelwin && !gpi_modelwin(gpi)) {
3623 menu_update = update = 1;
3624 } else if (uses_subdir && !gpi_subdir(gpi)) {
3625 update = 1;
3626 } else if (dreq != gpi->dreq) {
3627 update = 1;
3628 } else if (modelreq != gpi->modelreq) {
3629 update = 1;
3630 }
3631 } else {
3632 gpi = get_new_package_info(&err);
3633 menu_update = update = 1;
3634 replace = 0;
3635 }
3636
3637 fprintf(stderr, "update_gui_package_info: update=%d, menu_update=%d, "
3638 "err=%d\n", update, menu_update, err);
3639
3640 if (!err && menu_update && gpi->merge_id > 0) {
3641 /* trash stale UI info */
3642 destroy_gpi_ui(gpi);
3643 }
3644
3645 if (!err && update) {
3646 err = fill_gpi_entry(gpi,
3647 pkgname,
3648 fname,
3649 label,
3650 relpath,
3651 modelwin,
3652 uses_subdir,
3653 dreq,
3654 modelreq,
3655 replace);
3656 }
3657
3658 if (update && !err) {
3659 gpkgs_changed = 1;
3660 if (menu_update) {
3661 if (!modelwin) {
3662 /* add to main-window menu */
3663 add_package_to_menu(gpi, mdata);
3664 }
3665 }
3666 /* sync GUI */
3667 maybe_update_pkg_registry_window(pkgname, MENU_ADD_FN_PKG);
3668 }
3669
3670 return err;
3671 }
3672
3673 /* read "packages.xml" to find out what's what among packages
3674 that offer to place themselves in the gretl menu system
3675 */
3676
gui_package_info_init(void)3677 static int gui_package_info_init (void)
3678 {
3679 gchar *fname;
3680 int err, n = 0;
3681
3682 /* start with the "system" packages.xml, which should
3683 always be present */
3684 fname = packages_xml_path(SYS_PACKAGES);
3685 err = read_packages_file(fname, &n, SYS_PACKAGES);
3686 #if PKG_DEBUG
3687 fprintf(stderr, "read_packages_file: n=%d, err=%d from '%s'\n",
3688 n, err, fname);
3689 #endif
3690 g_free(fname);
3691
3692 if (!err) {
3693 /* then read the per-user packages.xml, if present */
3694 fname = packages_xml_path(USER_PACKAGES);
3695 #if PKG_DEBUG
3696 fprintf(stderr, "now trying '%s'\n", fname);
3697 #endif
3698 if (gretl_file_exists(fname)) {
3699 err = read_packages_file(fname, &n, USER_PACKAGES);
3700 #if PKG_DEBUG
3701 fprintf(stderr, "read_packages_file: n=%d, err=%d from '%s'\n",
3702 n, err, fname);
3703 #endif
3704 }
3705 g_free(fname);
3706 }
3707
3708 if (err) {
3709 destroy_gui_package_info();
3710 } else {
3711 n_gpkgs = n;
3712 }
3713
3714 return err;
3715 }
3716
3717 /* For function packages offering a menu attachment point: given the
3718 internal package name (e.g. "gig") and a menu path where we'd like
3719 it to appear (e.g. "/menubar/Model/TSModels" -- see the ui
3720 definition file gui/gretlmain.xml), construct the appropriate menu
3721 item and connect it to gfn_menu_callback(), for which see above.
3722
3723 This is called for both main-window and model-window menu
3724 attachments.
3725 */
3726
add_package_to_menu(gui_package_info * gpi,windata_t * vwin)3727 static void add_package_to_menu (gui_package_info *gpi,
3728 windata_t *vwin)
3729 {
3730 static GtkActionEntry item = {
3731 NULL, NULL, NULL, NULL, NULL, G_CALLBACK(gfn_menu_callback)
3732 };
3733 gchar *fixed_label = NULL;
3734 guint merge_id;
3735
3736 #if PKG_DEBUG
3737 fprintf(stderr, "add_package_to_menu:\n pkgname='%s', menupath='%s', label='%s'\n",
3738 gpi->pkgname, gpi->menupath, gpi->label);
3739 #endif
3740
3741 item.name = gpi->pkgname;
3742 item.label = gpi->label != NULL ? gpi->label : gpi->pkgname;
3743
3744 if (strchr(item.label, '_')) {
3745 fixed_label = double_underscores_new(item.label);
3746 item.label = fixed_label;
3747 }
3748
3749 merge_id = gtk_ui_manager_new_merge_id(vwin->ui);
3750 gtk_ui_manager_add_ui(vwin->ui, merge_id, gpi->menupath,
3751 _(item.label), item.name,
3752 GTK_UI_MANAGER_MENUITEM,
3753 FALSE);
3754 if (vwin == mdata) {
3755 gpi->merge_id = merge_id;
3756 }
3757
3758 gpi->ag = gtk_action_group_new(item.name);
3759 gtk_action_group_set_translation_domain(gpi->ag, "gretl");
3760 gtk_action_group_add_actions(gpi->ag, &item, 1, vwin);
3761 if (gpi->flags & GPI_DATAREQ) {
3762 g_object_set_data(G_OBJECT(gpi->ag), "datareq", GINT_TO_POINTER(1));
3763 }
3764 gtk_ui_manager_insert_action_group(vwin->ui, gpi->ag, 0);
3765 // g_object_unref(gpi->ag);
3766
3767 g_free(fixed_label);
3768 #if PKG_DEBUG
3769 fprintf(stderr, " merge_id = %d\n", merge_id);
3770 #endif
3771 }
3772
3773 /* run a package's gui-precheck function to determine if
3774 it's OK to add its GUI interface to a gretl
3775 model-window menu
3776 */
3777
precheck_error(ufunc * func,windata_t * vwin)3778 static int precheck_error (ufunc *func, windata_t *vwin)
3779 {
3780 PRN *prn;
3781 double check_err = 0;
3782 void *ptr = NULL;
3783 int err = 0;
3784
3785 prn = gretl_print_new(GRETL_PRINT_STDERR, &err);
3786 set_genr_model_from_vwin(vwin);
3787 err = gretl_function_exec(fncall_new(func, 0), GRETL_TYPE_DOUBLE,
3788 dataset, &ptr, NULL, prn);
3789 check_err = *(double *) ptr;
3790 unset_genr_model();
3791 gretl_print_destroy(prn);
3792
3793 if (err == 0 && check_err != 0) {
3794 err = 1;
3795 }
3796
3797 return err;
3798 }
3799
maybe_add_model_pkg(gui_package_info * gpi,windata_t * vwin)3800 static int maybe_add_model_pkg (gui_package_info *gpi,
3801 windata_t *vwin)
3802 {
3803 int ci, dreq, modelreq, minver = 0;
3804 gchar *precheck = NULL;
3805 fnpkg *pkg;
3806 int err = 0;
3807
3808 if (vwin->role == VIEW_MODEL) {
3809 MODEL *pmod = vwin->data;
3810
3811 ci = pmod->ci;
3812 } else {
3813 /* system: VAR, VECM or SYSTEM */
3814 ci = vwin->role;
3815 }
3816
3817 #if MPKG_DEBUG
3818 fprintf(stderr, "maybe_add_model_pkg: %s, ci=%s\n",
3819 gpi->pkgname, gretl_command_word(ci));
3820 #endif
3821
3822 if (gpi->modelreq > 0 && ci != gpi->modelreq) {
3823 return 0;
3824 }
3825
3826 if (gpi->filepath == NULL) {
3827 gpi->filepath =
3828 gretl_function_package_get_path(gpi->pkgname, gpi_ptype(gpi));
3829 }
3830
3831 if (gpi->filepath == NULL) {
3832 fprintf(stderr, "%s: couldn't find it\n", gpi->pkgname);
3833 return E_FOPEN;
3834 }
3835
3836 pkg = get_function_package_by_filename(gpi->filepath, &err);
3837
3838 if (!err) {
3839 err = function_package_get_properties(pkg,
3840 "data-requirement", &dreq,
3841 "model-requirement", &modelreq,
3842 "min-version", &minver,
3843 "gui-precheck", &precheck,
3844 NULL);
3845 }
3846
3847 if (!err) {
3848 /* "skip" means skip this package, since it won't work
3849 with the current model */
3850 int skip = 0;
3851
3852 if (modelreq > 0) {
3853 skip = ci != modelreq;
3854 }
3855 if (!skip) {
3856 skip = check_function_needs(dataset, dreq, minver);
3857 }
3858 if (!skip && precheck != NULL) {
3859 ufunc *func = get_function_from_package(precheck, pkg);
3860
3861 if (func == NULL || precheck_error(func, vwin)) {
3862 skip = 1;
3863 }
3864 }
3865 if (!skip) {
3866 add_package_to_menu(gpi, vwin);
3867 }
3868 }
3869
3870 g_free(precheck);
3871
3872 return err;
3873 }
3874
3875 /* Called from gretl.c on initializing the GUI: put suitable
3876 function packages (other than those that are designed to
3877 appear in model-window menus) into the appropriate main-
3878 window menus.
3879 */
3880
maybe_add_packages_to_menus(windata_t * vwin)3881 void maybe_add_packages_to_menus (windata_t *vwin)
3882 {
3883 gui_package_info *gpi;
3884 int i;
3885
3886 #if PKG_DEBUG
3887 fprintf(stderr, "starting maybe_add_packages_to_menus\n");
3888 #endif
3889
3890 if (gpkgs == NULL) {
3891 gui_package_info_init();
3892 }
3893
3894 #if PKG_DEBUG
3895 fprintf(stderr, " n_gpkgs = %d\n", n_gpkgs);
3896 #endif
3897
3898 for (i=0; i<n_gpkgs; i++) {
3899 gpi = &gpkgs[i];
3900 if (gpi->pkgname != NULL && !gpi_modelwin(gpi)) {
3901 add_package_to_menu(gpi, vwin);
3902 }
3903 }
3904
3905 #if PKG_DEBUG
3906 fprintf(stderr, "finished maybe_add_packages_to_menus\n");
3907 #endif
3908 }
3909
3910 /* Called from gui_utils.c when setting up the UI for a
3911 model window.
3912 */
3913
maybe_add_packages_to_model_menus(windata_t * vwin)3914 void maybe_add_packages_to_model_menus (windata_t *vwin)
3915 {
3916 gui_package_info *gpi;
3917 int i, err;
3918
3919 #if MPKG_DEBUG
3920 fprintf(stderr, "starting maybe_add_packages_to_model_menus\n");
3921 #endif
3922
3923 if (gpkgs == NULL) {
3924 gui_package_info_init();
3925 }
3926
3927 #if MPKG_DEBUG
3928 fprintf(stderr, " n_gpkgs = %d\n", n_gpkgs);
3929 #endif
3930
3931 for (i=0; i<n_gpkgs; i++) {
3932 gpi = &gpkgs[i];
3933 if (gpi->pkgname != NULL && gpi_modelwin(gpi)) {
3934 err = maybe_add_model_pkg(gpi, vwin);
3935 if (err) {
3936 if (err == E_FOPEN && gpi_sysfile(gpi)) {
3937 ;
3938 } else {
3939 /* delete entry from registry */
3940 gui_function_pkg_unregister(gpi->pkgname);
3941 }
3942 }
3943 }
3944 }
3945 }
3946
3947 /* Below: apparatus for activation when the user installs a function
3948 package (other than an official addon) from the gretl server.
3949
3950 We check to see if (a) the package offers a menu attachment, and if
3951 so (b) that the package is not already "registered" in the user's
3952 packages.xml file. If both of these conditions are met we put up a
3953 dialog asking if the user wants to add the package to the menu
3954 system. If the answer is Yes we write an appropriate entry into
3955 packages.xml, or write this file from scratch if it doesn't yet
3956 exist.
3957 */
3958
3959 /* Find out where the package is supposed to attach: the
3960 @mpath string (which gets into the gfn file from its
3961 associated spec file or the GUI) should look something like
3962
3963 MODELWIN/Analysis or
3964 MAINWIN/Model
3965
3966 The first portion just tells us in which window it should
3967 appear.
3968 */
3969
pkg_get_attachment(const gchar * mpath,int * modelwin)3970 static gchar *pkg_get_attachment (const gchar *mpath,
3971 int *modelwin)
3972 {
3973 const gchar *src = mpath;
3974 gchar *relpath = NULL;
3975
3976 #if PKG_DEBUG
3977 fprintf(stderr, "pkg_get_attachment: mpath = '%s'\n", mpath);
3978 #endif
3979
3980 if (!strncmp(mpath, "MAINWIN/", 8)) {
3981 src = mpath + 7;
3982 } else if (!strncmp(mpath, "menubar/", 8)) {
3983 /* backward compatibility for old packages */
3984 src = mpath + 7;
3985 } else if (!strncmp(mpath, "MODELWIN/", 9)) {
3986 src = mpath + 8;
3987 *modelwin = 1;
3988 }
3989
3990 if (!strcmp(src, "/Model/TSModels/TSMulti")) {
3991 relpath = g_strdup("/Model/TSMulti");
3992 } else {
3993 relpath = g_strdup(src);
3994 }
3995
3996 return relpath;
3997 }
3998
pkg_attach_query(const gchar * name,const gchar * label,const gchar * relpath,int modelwin,GtkWidget * parent)3999 static int pkg_attach_query (const gchar *name,
4000 const gchar *label,
4001 const gchar *relpath,
4002 int modelwin,
4003 GtkWidget *parent)
4004 {
4005 int resp = -1;
4006
4007 if (relpath != NULL && *relpath != '\0') {
4008 const gchar *window_names[] = {
4009 N_("main window"),
4010 N_("model window")
4011 };
4012 gchar *msg, *ustr = NULL;
4013
4014 ustr = user_friendly_menu_path(relpath, modelwin);
4015 if (ustr == NULL) {
4016 errbox_printf("Invalid menu path '%s'", relpath);
4017 } else {
4018 msg = g_strdup_printf(_("The package %s can be attached to the "
4019 "gretl menus\n"
4020 "as \"%s/%s\" in the %s.\n"
4021 "Do you want to do this?"),
4022 name, ustr ? ustr : relpath, _(label),
4023 modelwin ? _(window_names[1]) :
4024 _(window_names[0]));
4025 resp = yes_no_dialog(NULL, msg, parent);
4026 g_free(msg);
4027 g_free(ustr);
4028 }
4029 }
4030
4031 return resp;
4032 }
4033
4034 /* Called from fnsave.c, when edits to a function package
4035 are being saved.
4036 */
4037
gui_function_pkg_revise_status(const gchar * pkgname,const gchar * fname,const gchar * label,const gchar * mpath,gboolean uses_subdir,DataReq dreq,int modelreq)4038 int gui_function_pkg_revise_status (const gchar *pkgname,
4039 const gchar *fname,
4040 const gchar *label,
4041 const gchar *mpath,
4042 gboolean uses_subdir,
4043 DataReq dreq,
4044 int modelreq)
4045 {
4046 gui_package_info *gpi;
4047 int has_attachment = 0;
4048 int do_update = 0;
4049 int err = 0;
4050
4051 /* In this context we may, in principle, be adding,
4052 removing, or revising the gui-menu status of
4053 a package.
4054 */
4055
4056 if (label != NULL && mpath != NULL) {
4057 has_attachment = 1;
4058 }
4059
4060 gpi = get_gpi_entry(pkgname);
4061
4062 if (gpi == NULL) {
4063 /* not in registry yet */
4064 if (has_attachment) {
4065 do_update = 1;
4066 }
4067 } else {
4068 /* already in registry */
4069 if (has_attachment) {
4070 do_update = 1;
4071 } else {
4072 gui_function_pkg_unregister(pkgname);
4073 }
4074 }
4075
4076 if (do_update) {
4077 gchar *relpath;
4078 int modelwin = 0;
4079
4080 relpath = pkg_get_attachment(mpath, &modelwin);
4081 err = update_gui_package_info(pkgname,
4082 fname,
4083 label,
4084 relpath,
4085 modelwin,
4086 uses_subdir,
4087 dreq,
4088 modelreq);
4089 if (err) {
4090 gui_errmsg(err);
4091 }
4092 g_free(relpath);
4093 }
4094
4095 return err;
4096 }
4097
pkg_get_data_requirement(GtkActionGroup * ag)4098 DataReq pkg_get_data_requirement (GtkActionGroup *ag)
4099 {
4100 int i;
4101
4102 for (i=0; i<n_gpkgs; i++) {
4103 if (gpkgs[i].ag == ag) {
4104 return gpkgs[i].dreq;
4105 }
4106 }
4107
4108 return 0;
4109 }
4110
4111 /* Remove a package from the in-memory representation of
4112 menu-attached packages.
4113 */
4114
gui_function_pkg_unregister(const gchar * pkgname)4115 void gui_function_pkg_unregister (const gchar *pkgname)
4116 {
4117 gui_package_info *gpi;
4118
4119 gpi = get_gpi_entry(pkgname);
4120 if (gpi != NULL) {
4121 clear_gpi_entry(gpi);
4122 }
4123
4124 /* sync the package registry window, if it happens to
4125 be open currently */
4126 maybe_update_pkg_registry_window(pkgname, DELETE_FN_PKG);
4127 }
4128
in_own_subdir(const char * pkgname,const char * path)4129 static int in_own_subdir (const char *pkgname, const char *path)
4130 {
4131 gchar *test;
4132 int ret = 0;
4133
4134 /* e.g. "mypkg/mypkg" */
4135 test = g_strdup_printf("%s%c%s", pkgname, SLASH, pkgname);
4136
4137 if (strstr(path, test) != NULL) {
4138 ret = 1;
4139 } else {
4140 gretl_errmsg_sprintf("The function file %s.gfn is not installed correctly:\n"
4141 "it should be in a subdirectory named '%s'.",
4142 pkgname, pkgname);
4143 }
4144
4145 g_free(test);
4146
4147 return ret;
4148 }
4149
4150 /* Actually do the business of registering a function package
4151 to appear in a menu */
4152
gui_function_pkg_register(const char * fname,const char * pkgname,const char * label,const char * relpath,int modelwin)4153 static int gui_function_pkg_register (const char *fname,
4154 const char *pkgname,
4155 const char *label,
4156 const char *relpath,
4157 int modelwin)
4158 {
4159 GtkWidget *editor;
4160 fnpkg *pkg = NULL;
4161 int err = 0;
4162
4163 if (package_being_edited(pkgname, &editor)) {
4164 pkg = package_editor_get_pkg(editor);
4165 }
4166
4167 if (pkg == NULL) {
4168 pkg = get_function_package_by_filename(fname, &err);
4169 }
4170
4171 if (pkg == NULL) {
4172 errbox_printf(_("Couldn't read '%s'"), fname);
4173 return E_FOPEN;
4174 }
4175
4176 #if PKG_DEBUG
4177 fprintf(stderr, "gui_function_pkg_register: %s: err = %d\n", fname, err);
4178 #endif
4179
4180 if (!err) {
4181 int uses_subdir = 0;
4182 DataReq dreq = 0;
4183 int modelreq = 0;
4184
4185 err = function_package_get_properties(pkg,
4186 "lives-in-subdir",
4187 &uses_subdir,
4188 "data-requirement",
4189 &dreq,
4190 "model-requirement",
4191 &modelreq,
4192 NULL);
4193
4194 if (!err && !uses_subdir) {
4195 /* fallback detection: packages that have PDF doc
4196 must be in their own subdir */
4197 uses_subdir = function_package_has_PDF_doc(pkg, NULL);
4198 }
4199
4200 if (!err && uses_subdir && !in_own_subdir(pkgname, fname)) {
4201 /* detect mis-installed package: should be in
4202 own subdirectory but is not */
4203 err = E_DATA;
4204 }
4205
4206 if (!err) {
4207 err = update_gui_package_info(pkgname,
4208 fname,
4209 label,
4210 relpath,
4211 modelwin,
4212 uses_subdir,
4213 dreq,
4214 modelreq);
4215 }
4216 }
4217
4218 if (err) {
4219 gui_errmsg(err);
4220 }
4221
4222 return err;
4223 }
4224
4225 /* The following is called in two contexts:
4226
4227 (1) From the handler for installing a function package from the
4228 gretl server.
4229
4230 (2) From the popup menu-item or button "Add to menu" in the window
4231 displaying installed function packages.
4232
4233 We return non-zero if we show a dialog here: that's for the
4234 benefit of the installation handler, to tell it not to put
4235 up a second, redundant confirmation dialog.
4236 */
4237
gui_function_pkg_query_register(const char * fname,GtkWidget * parent)4238 int gui_function_pkg_query_register (const char *fname,
4239 GtkWidget *parent)
4240 {
4241 char *pkgname = NULL;
4242 char *menupath = NULL;
4243 char *label = NULL;
4244 int notified = 0;
4245
4246 if (package_has_menu_attachment(fname, &pkgname, &menupath,
4247 &label)) {
4248 gchar *relpath;
4249 int resp, modelwin = 0;
4250
4251 relpath = pkg_get_attachment(menupath, &modelwin);
4252 resp = pkg_attach_query(pkgname, label, relpath,
4253 modelwin, parent);
4254 if (resp == GRETL_YES) {
4255 gui_function_pkg_register(fname, pkgname,
4256 label, relpath,
4257 modelwin);
4258 }
4259 notified = 1;
4260 g_free(relpath);
4261 }
4262
4263 free(pkgname);
4264 free(menupath);
4265 free(label);
4266
4267 return notified;
4268 }
4269
installed_addon_status_string(const char * path,const char * svstr,int minver)4270 char *installed_addon_status_string (const char *path,
4271 const char *svstr,
4272 int minver)
4273 {
4274 char *ivstr = NULL;
4275 char *ret = NULL;
4276
4277 /* @ivstr = installed package version string
4278 @svstr = package version string from server
4279 @minver = gretl version required for pkg on server
4280 */
4281
4282 ivstr = get_addon_version(path, NULL);
4283
4284 if (ivstr != NULL) {
4285 double svnum = dot_atof(svstr);
4286 double ivnum = dot_atof(ivstr);
4287 int current = 0;
4288 int update_ok = 0;
4289 char reqstr[8] = {0};
4290
4291 current = ivnum >= svnum;
4292
4293 if (!current) {
4294 /* Not current, but can the addon be updated? It may
4295 be that the running instance of gretl is too old.
4296 */
4297 update_ok = package_version_ok(minver, reqstr);
4298 }
4299
4300 if (current) {
4301 ret = gretl_strdup(_("Up to date"));
4302 } else if (update_ok) {
4303 ret = gretl_strdup(_("Not up to date"));
4304 } else if (*reqstr != '\0') {
4305 ret = gretl_strdup_printf(_("Requires gretl %s"), reqstr);
4306 }
4307 free(ivstr);
4308 }
4309
4310 if (ret == NULL) {
4311 ret = gretl_strdup(_("Error reading package"));
4312 }
4313
4314 return ret;
4315 }
4316
4317 /* We invoke this function on the two GUI "entry-points" to
4318 dbnomics, namely retrieving a specified series and getting
4319 the current list of providers. We thereby ensure that if
4320 the dbnomics function package is not found on the local
4321 machine we try to download and install it.
4322
4323 We also invoke it for regls, which requires a distinct
4324 saved path.
4325 */
4326
get_addon_function_call(const char * addon,const char * funcname)4327 static fncall *get_addon_function_call (const char *addon,
4328 const char *funcname)
4329 {
4330 static char *dbnpath;
4331 static char *rlspath;
4332 char **ppkgpath = NULL;
4333 fncall *fc = NULL;
4334 int err = 0;
4335
4336 if (!strcmp(addon, "dbnomics")) {
4337 ppkgpath = &dbnpath;
4338 } else if (!strcmp(addon, "regls")) {
4339 ppkgpath = &rlspath;
4340 } else {
4341 err = E_DATA;
4342 }
4343
4344 if (!err && *ppkgpath == NULL) {
4345 *ppkgpath = gretl_addon_get_path(addon);
4346 if (*ppkgpath == NULL) {
4347 /* not found locally */
4348 err = download_addon(addon, ppkgpath);
4349 }
4350 }
4351
4352 if (!err && *ppkgpath != NULL) {
4353 fc = get_pkg_function_call(funcname, addon, *ppkgpath);
4354 }
4355
4356 return fc;
4357 }
4358
dbnomics_report_error(const char * datacode,gretl_bundle * b,PRN ** pprn)4359 static void dbnomics_report_error (const char *datacode,
4360 gretl_bundle *b,
4361 PRN **pprn)
4362 {
4363 const char *buf = gretl_print_get_buffer(*pprn);
4364
4365 if (!string_is_blank(buf)) {
4366 /* show what we got via PRN */
4367 gchar *title = g_strdup_printf("gretl: %s", datacode);
4368
4369 view_buffer(*pprn, 78, 200, title, IMPORT, NULL);
4370 *pprn = NULL; /* ownership taken by viewer */
4371 g_free(title);
4372 } else {
4373 const char *errmsg = gretl_bundle_get_string(b, "errmsg", NULL);
4374
4375 if (!string_is_blank(errmsg)) {
4376 errbox(errmsg);
4377 } else {
4378 /* fallback */
4379 gchar *msg = g_strdup_printf(_("%s: no data found"), datacode);
4380
4381 errbox(msg);
4382 g_free(msg);
4383 }
4384 }
4385 }
4386
4387 /* below: callbacks from regular gretl GUI menu items/buttons
4388 that invoke calls to the dbnomics package in the background
4389 */
4390
dbnomics_get_series_call(const char * datacode)4391 int dbnomics_get_series_call (const char *datacode)
4392 {
4393 gretl_bundle *b = NULL;
4394 fncall *fc = NULL;
4395 PRN *prn = NULL;
4396 int err = 0;
4397
4398 err = bufopen(&prn);
4399
4400 if (!err) {
4401 fc = get_addon_function_call("dbnomics", "dbnomics_get_series");
4402 if (fc == NULL) {
4403 gretl_print_destroy(prn);
4404 err = E_DATA;
4405 }
4406 }
4407
4408 if (err) {
4409 return err;
4410 }
4411
4412 err = push_anon_function_arg(fc, GRETL_TYPE_STRING, (void *) datacode);
4413 if (!err) {
4414 err = gretl_function_exec(fc, GRETL_TYPE_BUNDLE, dataset,
4415 &b, NULL, prn);
4416 if (err) {
4417 gui_errmsg(err);
4418 }
4419 }
4420
4421 if (b != NULL) {
4422 int dberr = gretl_bundle_get_int(b, "error", &err);
4423
4424 if (dberr) {
4425 /* we need to handle the case where dbnomics failed
4426 but did not provide any error message
4427 */
4428 dbnomics_report_error(datacode, b, &prn);
4429 gretl_bundle_destroy(b);
4430 } else {
4431 const char *p = strrchr(datacode, '/');
4432 gchar *title;
4433
4434 title = g_strdup_printf("gretl: %s", p + 1);
4435 fc = get_pkg_function_call("dbnomics_bundle_print", "dbnomics", NULL);
4436 if (fc != NULL) {
4437 err = push_anon_function_arg(fc, GRETL_TYPE_BUNDLE, (void *) b);
4438 if (!err) {
4439 err = gretl_function_exec(fc, GRETL_TYPE_NONE, dataset,
4440 NULL, NULL, prn);
4441 if (err) {
4442 gui_errmsg(err);
4443 } else {
4444 view_buffer(prn, 78, 350, title, VIEW_DBNOMICS, b);
4445 prn = NULL; /* ownership taken by viewer */
4446 }
4447 }
4448 }
4449 g_free(title);
4450 }
4451 }
4452
4453 gretl_print_destroy(prn);
4454
4455 return err;
4456 }
4457
dbnomics_get_dimensions_call(const char * provider,const char * dsname)4458 int dbnomics_get_dimensions_call (const char *provider,
4459 const char *dsname)
4460 {
4461 fncall *fc = NULL;
4462 double one = 1;
4463 PRN *prn = NULL;
4464 int err;
4465
4466 err = bufopen(&prn);
4467
4468 if (!err) {
4469 fc = get_addon_function_call("dbnomics", "dbnomics_get_dataset_dimensions");
4470 if (fc == NULL) {
4471 gretl_print_destroy(prn);
4472 err = E_DATA;
4473 }
4474 }
4475
4476 if (err) {
4477 return err;
4478 }
4479
4480 pprintf(prn, "Information on dbnomics dataset %s/%s (may be quite voluminous)\n\n",
4481 provider, dsname);
4482 pputs(prn, "This may indicate (as applicable):\n"
4483 " * topics covered by the dataset\n"
4484 " * countries included\n"
4485 " * units of measurement\n"
4486 " * other information\n\n");
4487
4488 err = push_anon_function_arg(fc, GRETL_TYPE_STRING, (void *) provider);
4489 if (!err) {
4490 err = push_anon_function_arg(fc, GRETL_TYPE_STRING, (void *) dsname);
4491 }
4492 if (!err) {
4493 /* verbosity */
4494 err = push_anon_function_arg(fc, GRETL_TYPE_DOUBLE, (void *) &one);
4495 }
4496 if (!err) {
4497 GdkWindow *cwin = NULL;
4498
4499 set_wait_cursor(&cwin);
4500 err = gretl_function_exec(fc, GRETL_TYPE_NONE, dataset,
4501 NULL, NULL, prn);
4502 unset_wait_cursor(cwin);
4503 }
4504
4505 if (err) {
4506 gui_errmsg(err);
4507 gretl_print_destroy(prn);
4508 } else {
4509 gchar *title;
4510
4511 title = g_strdup_printf("gretl: %s/%s", provider, dsname);
4512 view_buffer(prn, 80, 500, title, PRINT, NULL);
4513 g_free(title);
4514 }
4515
4516 return err;
4517 }
4518
dbnomics_get_providers_call(int * err)4519 void *dbnomics_get_providers_call (int *err)
4520 {
4521 gretl_array *A = NULL;
4522 fncall *fc = NULL;
4523 GdkWindow *cwin = NULL;
4524
4525 fc = get_addon_function_call("dbnomics", "dbnomics_providers");
4526 if (fc == NULL) {
4527 *err = E_DATA;
4528 return NULL;
4529 }
4530
4531 set_wait_cursor(&cwin);
4532 *err = gretl_function_exec(fc, GRETL_TYPE_BUNDLES, dataset,
4533 &A, NULL, NULL);
4534 unset_wait_cursor(cwin);
4535 if (*err) {
4536 gui_errmsg(*err);
4537 }
4538
4539 return A;
4540 }
4541
dbnomics_search_call(const char * key,const char * prov,const char * dset,int limit,int offset,int * err)4542 void *dbnomics_search_call (const char *key,
4543 const char *prov,
4544 const char *dset,
4545 int limit, int offset,
4546 int *err)
4547 {
4548 gretl_array *A = NULL;
4549 fncall *fc = NULL;
4550 int use_dset = 0;
4551
4552 if (prov != NULL && dset != NULL) {
4553 use_dset = 1;
4554 fc = get_pkg_function_call("dset_search", "dbnomics", NULL);
4555 } else {
4556 fc = get_pkg_function_call("general_search", "dbnomics", NULL);
4557 }
4558 if (fc == NULL) {
4559 *err = E_DATA;
4560 return NULL;
4561 }
4562
4563 if (use_dset) {
4564 *err = push_function_args(fc, GRETL_TYPE_STRING, (void *) key,
4565 GRETL_TYPE_STRING, (void *) prov,
4566 GRETL_TYPE_STRING, (void *) dset,
4567 GRETL_TYPE_INT, (void *) &limit,
4568 GRETL_TYPE_INT, (void *) &offset, -1);
4569 } else {
4570 *err = push_function_args(fc, GRETL_TYPE_STRING, (void *) key,
4571 GRETL_TYPE_INT, (void *) &limit,
4572 GRETL_TYPE_INT, (void *) &offset, -1);
4573 }
4574
4575 if (!*err) {
4576 GdkWindow *cwin = NULL;
4577
4578 set_wait_cursor(&cwin);
4579 *err = gretl_function_exec(fc, GRETL_TYPE_BUNDLES, dataset,
4580 &A, NULL, NULL);
4581 unset_wait_cursor(cwin);
4582 }
4583
4584 if (*err) {
4585 gui_errmsg(*err);
4586 }
4587
4588 return A;
4589 }
4590
dbnomics_dataset_list(const char * provider,int * err)4591 void *dbnomics_dataset_list (const char *provider, int *err)
4592 {
4593 gretl_bundle *b = NULL;
4594 fncall *fc = NULL;
4595
4596 fc = get_pkg_function_call("dbnomics_dsets_for_provider",
4597 "dbnomics", NULL);
4598 if (fc == NULL) {
4599 *err = E_DATA;
4600 return NULL;
4601 }
4602
4603 *err = push_anon_function_arg(fc, GRETL_TYPE_STRING, (void *) provider);
4604 if (!*err) {
4605 GdkWindow *cwin = NULL;
4606
4607 set_wait_cursor(&cwin);
4608 *err = gretl_function_exec(fc, GRETL_TYPE_BUNDLE, dataset,
4609 &b, NULL, NULL);
4610 unset_wait_cursor(cwin);
4611 }
4612 if (*err) {
4613 gui_errmsg(*err);
4614 }
4615
4616 return b;
4617 }
4618
dbnomics_probe_series(const char * prov,const char * dset,int limit,int offset,int * err)4619 void *dbnomics_probe_series (const char *prov,
4620 const char *dset,
4621 int limit, int offset,
4622 int *err)
4623 {
4624 gretl_array *A = NULL;
4625 fncall *fc = NULL;
4626
4627 fc = get_pkg_function_call("dbnomics_get_dataset_content",
4628 "dbnomics", NULL);
4629 if (fc == NULL) {
4630 *err = E_DATA;
4631 return NULL;
4632 }
4633
4634 *err = push_function_args(fc, GRETL_TYPE_STRING, (void *) prov,
4635 GRETL_TYPE_STRING, (void *) dset,
4636 GRETL_TYPE_INT, (void *) &limit,
4637 GRETL_TYPE_INT, (void *) &offset, -1);
4638 if (!*err) {
4639 GdkWindow *cwin = NULL;
4640
4641 set_wait_cursor(&cwin);
4642 *err = gretl_function_exec(fc, GRETL_TYPE_BUNDLES, dataset,
4643 &A, NULL, NULL);
4644 unset_wait_cursor(cwin);
4645 }
4646
4647 if (*err) {
4648 gui_errmsg(*err);
4649 }
4650
4651 return A;
4652 }
4653
real_do_regls(const char * buf)4654 int real_do_regls (const char *buf)
4655 {
4656 gretl_bundle *parms = selector_get_regls_bundle();
4657 gretl_bundle *rb = NULL;
4658 fncall *fc = NULL;
4659 int orig_v;
4660 int *X = NULL;
4661 PRN *prn = NULL;
4662 int err = 0;
4663
4664 if (parms == NULL) {
4665 errbox("regls: no parameters bundle");
4666 return E_DATA;
4667 }
4668
4669 fc = get_addon_function_call("regls", "regls");
4670 if (fc == NULL) {
4671 errbox("regls: couldn't find regls()");
4672 return E_DATA;
4673 }
4674
4675 bufopen(&prn);
4676 orig_v = dataset->v;
4677
4678 X = generate_list(buf, dataset, &err);
4679 if (!err) {
4680 int yno = X[1];
4681
4682 gretl_list_delete_at_pos(X, 1);
4683 err = push_function_arg(fc, dataset->varname[yno], NULL,
4684 GRETL_TYPE_USERIES, &yno);
4685 if (!err) {
4686 err = push_function_args(fc, GRETL_TYPE_LIST, (void *) X,
4687 GRETL_TYPE_BUNDLE, (void *) parms, -1);
4688 }
4689 }
4690
4691 if (!err) {
4692 GdkWindow *cwin = NULL;
4693
4694 set_wait_cursor(&cwin);
4695 err = gretl_function_exec(fc, GRETL_TYPE_BUNDLE, dataset,
4696 &rb, NULL, prn);
4697 unset_wait_cursor(cwin);
4698 if (!err) {
4699 view_buffer(prn, 78, 350, "gretl: regls", VIEW_BUNDLE, rb);
4700 prn = NULL; /* ownership taken by viewer */
4701 }
4702 if (dataset->v > orig_v) {
4703 /* in case any lags got added */
4704 populate_varlist();
4705 }
4706 }
4707
4708 if (err) {
4709 gui_errmsg(err);
4710 }
4711
4712 free(X);
4713 gretl_print_destroy(prn);
4714
4715 return err;
4716 }
4717
4718 /* geomap related functions */
4719
plausible_payload_list(int v,int * selpos)4720 static GList *plausible_payload_list (int v, int *selpos)
4721 {
4722 GList *list = NULL;
4723 int i, j = 1;
4724
4725 for (i=dataset->v-1; i>0; i--) {
4726 if (!is_string_valued(dataset, i) &&
4727 !gretl_isconst(dataset->t1, dataset->t2, dataset->Z[i])) {
4728 list = g_list_append(list, (gpointer) dataset->varname[i]);
4729 if (i == v) {
4730 *selpos = j;
4731 }
4732 j++;
4733 }
4734 }
4735
4736 if (list != NULL) {
4737 list = g_list_prepend(list, (gpointer) "none");
4738 }
4739
4740 return list;
4741 }
4742
4743 /* Called in response to "Display map" */
4744
map_plot_callback(int v)4745 void map_plot_callback (int v)
4746 {
4747 const char *mapfile = dataset_get_mapfile(dataset);
4748
4749 if (mapfile == NULL) {
4750 errbox(_("No mapfile is present"));
4751 } else {
4752 gretl_bundle *opts = NULL;
4753 GList *payload_list = NULL;
4754 double *payload = NULL;
4755 int payload_id = 0;
4756 int resp, selpos = 0;
4757 int err = 0;
4758
4759 opts = gretl_bundle_new();
4760 gretl_bundle_set_int(opts, "gui_auto", 1);
4761 payload_list = plausible_payload_list(v, &selpos);
4762
4763 /* get options from the user */
4764 resp = map_options_dialog(payload_list, selpos,
4765 opts, &payload_id);
4766 if (resp == GRETL_CANCEL) {
4767 return;
4768 }
4769 if (payload_list != NULL) {
4770 g_list_free(payload_list);
4771 }
4772 if (payload_id == 0) {
4773 /* just showing outlines */
4774 gretl_bundle_set_int(opts, "tics", 1);
4775 } else {
4776 payload = dataset->Z[payload_id];
4777 }
4778 err = geoplot_driver(mapfile, NULL, payload, dataset, opts);
4779 if (err) {
4780 gui_errmsg(err);
4781 } else {
4782 gchar *mapname = g_path_get_basename(mapfile);
4783
4784 gretl_bundle_set_string(opts, "mapname", mapname);
4785 gnuplot_show_map(opts);
4786 g_free(mapname);
4787 }
4788 gretl_bundle_destroy(opts);
4789 }
4790 }
4791