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 /* database.c for gretl */
21 
22 #include "gretl.h"
23 #include "boxplots.h"
24 #include "database.h"
25 #include "datafiles.h"
26 #include "gretl_xml.h"
27 #include "gretl_www.h"
28 #include "gretl_untar.h"
29 #include "gretl_zip.h"
30 #include "gretl_string_table.h"
31 #include "addons_utils.h"
32 #include "gretl_join.h"
33 #include "menustate.h"
34 #include "treeutils.h"
35 #include "textbuf.h"
36 #include "winstack.h"
37 #include "toolbar.h"
38 #include "dlgutils.h"
39 #include "fncall.h"
40 #include "dbread.h"
41 #include "fncall.h"
42 #include "varinfo.h"
43 
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <zlib.h>
48 #include <dirent.h>
49 #include <errno.h>
50 
51 #if G_BYTE_ORDER == G_BIG_ENDIAN
52 # include <netinet/in.h>
53 #endif
54 
55 #ifdef G_OS_WIN32
56 # include "gretlwin32.h"
57 #endif
58 
59 #define DB_SEARCH_DEBUG 0
60 
61 /* private functions */
62 static GtkWidget *database_window (windata_t *vwin);
63 static int add_local_db_series_list (windata_t *vwin);
64 static int add_remote_db_series_list (windata_t *vwin, char *buf);
65 static int add_rats_db_series_list (windata_t *vwin);
66 static int add_pcgive_db_series_list (windata_t *vwin);
67 static dbwrapper *get_db_series_info (windata_t *vwin, int action);
68 static int *db_get_selection_list (windata_t *vwin);
69 static void gui_get_db_series (windata_t *vwin, int cmd);
70 static void record_db_open_command (dbwrapper *dw);
71 
72 enum db_data_actions {
73     DB_DISPLAY,
74     DB_GRAPH,
75     DB_IMPORT
76 };
77 
78 enum db_codebook_type {
79     CB_NONE,
80     CB_TEXT,
81     CB_PDF
82 };
83 
84 /* columns of individual database window */
85 enum {
86     DBCOL_VARNAME,
87     DBCOL_DESCRIP,
88     DBCOL_OBSINFO,
89     DBCOL_OFFSET
90 };
91 
92 /* columns of list-of-databases window */
93 enum {
94     COL_DBNAME,
95     COL_DBINFO,
96     COL_DBPATH
97 };
98 
utf8_correct(char * orig)99 static int utf8_correct (char *orig)
100 {
101     int err = 0;
102 
103     if (!g_utf8_validate(orig, -1, NULL)) {
104 	GError *gerr = NULL;
105 	gchar *conv;
106 	gsize wrote;
107 
108 	conv = g_convert(orig, -1,
109 			 "UTF-8",
110 			 "ISO-8859-1",
111 			 NULL, &wrote, &gerr);
112 
113 	if (gerr != NULL) {
114 	    errbox(gerr->message);
115 	    g_error_free(gerr);
116 	    strcpy(orig, "invalid string");
117 	    err = 1;
118 	} else {
119 	    strcpy(orig, conv);
120 	    g_free(conv);
121 	}
122     }
123 
124     return err;
125 }
126 
update_statusline(windata_t * vwin,const char * s)127 static void update_statusline (windata_t *vwin, const char *s)
128 {
129     gchar *tmp = g_strdup_printf(_("Network status: %s"), s);
130 
131     gtk_label_set_text(GTK_LABEL(vwin->status), tmp);
132 
133     while (gtk_events_pending()) {
134 	gtk_main_iteration();
135     }
136 
137     g_free(tmp);
138 }
139 
set_time_series(DATASET * dset)140 static void set_time_series (DATASET *dset)
141 {
142     if (dset->pd != 1 || strcmp(dset->stobs, "1")) {
143 	dset->structure = TIME_SERIES;
144     }
145 }
146 
show_network_error(windata_t * vwin)147 void show_network_error (windata_t *vwin)
148 {
149     const char *msg = gretl_errmsg_get();
150     char *buf = NULL;
151 
152     if (*msg != '\0') {
153 	buf = gretl_strdup(msg);
154     }
155 
156     if (buf != NULL) {
157 	size_t n = strlen(buf);
158 
159 	if (buf[n-1] == '\n') {
160 	    buf[n-1] = '\0';
161 	}
162 	if (vwin != NULL) {
163 	    update_statusline(vwin, buf);
164 	} else {
165 	    errbox(buf);
166 	}
167 	free(buf);
168     } else if (vwin != NULL) {
169 	update_statusline(vwin, _("Error retrieving data from server"));
170     } else {
171 	errbox(_("Error retrieving data from server"));
172     }
173 }
174 
gui_get_remote_db_data(windata_t * vwin,SERIESINFO * sinfo,double ** Z)175 static int gui_get_remote_db_data (windata_t *vwin, SERIESINFO *sinfo,
176 				   double **Z)
177 {
178     char *dbbase = vwin->fname;
179     int err;
180 
181     update_statusline(vwin, _("Retrieving data..."));
182 
183     err = get_remote_db_data(dbbase, sinfo, Z);
184 
185     if (err) {
186 	show_network_error(vwin);
187 	return E_FOPEN;
188     } else {
189 	update_statusline(vwin, "OK");
190     }
191 
192     return err;
193 }
194 
display_dbdata(DATASET * dbset)195 static void display_dbdata (DATASET *dbset)
196 {
197     PRN *prn;
198     int width = 36;
199 
200     if (bufopen(&prn)) {
201 	return;
202     }
203 
204     if (dbset->v > 1) {
205 	width = 72;
206     }
207 
208     printdata(NULL, NULL, dbset, OPT_O, prn);
209     view_buffer(prn, width, 350, _("gretl: display database series"), PRINT,
210 		NULL);
211 }
212 
graph_dbdata(DATASET * dbset)213 static void graph_dbdata (DATASET *dbset)
214 {
215     int *list;
216     int err;
217 
218     list = gretl_consecutive_list_new(1, dbset->v - 1);
219     if (list == NULL) {
220 	nomem();
221 	return;
222     }
223 
224     if (dbset->structure == CROSS_SECTION) {
225 	err = boxplots(list, NULL, dbset, OPT_NONE);
226     } else {
227 	err = gnuplot(list, NULL, dbset, OPT_G | OPT_O | OPT_T);
228     }
229 
230     free(list);
231     gui_graph_handler(err);
232 }
233 
expand_data_dialog(int nx,int nv,GtkWidget * parent)234 static int expand_data_dialog (int nx, int nv, GtkWidget *parent)
235 {
236     const gchar *msg;
237 
238     if (nx == nv) {
239 	msg = N_("The data to be imported are of a lower frequency\n"
240 		 "than the current dataset. OK to proceed?");
241     } else {
242 	msg = N_("Some of the data to be imported are of a lower frequency\n"
243 		 "than the current dataset. OK to proceed?");
244     }
245 
246     return yes_no_help_dialog(_(msg), EXPAND, GRETL_YES);
247 }
248 
give_tdisagg_option(int v)249 static void give_tdisagg_option (int v)
250 {
251     gchar *msg;
252     int resp;
253 
254     msg = g_strdup_printf(_("Disaggregate %s now?"), dataset->varname[v]);
255     resp = yes_no_dialog("database import", msg, NULL);
256     g_free(msg);
257     if (resp == GRETL_YES) {
258 	tdisagg_dialog(v);
259     }
260 }
261 
obs_overlap_check(int pd,const char * stobs,const char * endobs,const char * varname)262 static int obs_overlap_check (int pd, const char *stobs,
263 			      const char *endobs,
264 			      const char *varname)
265 {
266     int err;
267 
268     err = db_range_check(pd, stobs, endobs, varname, dataset);
269     if (err) {
270 	gui_errmsg(err);
271     }
272 
273     return err;
274 }
275 
276 /* Handle the case of dbnomics pd != dataset->pd, for daily data */
277 
dbn_add_daily_data(windata_t * vwin,char * vname,DATASET * dset,PRN * prn)278 static int dbn_add_daily_data (windata_t *vwin, char *vname,
279 			       DATASET *dset, PRN *prn)
280 {
281     gretl_bundle *b = vwin->data;
282     gretl_array *S;
283     gretl_matrix *x;
284     gchar *tempname = NULL;
285     const char *obsstr;
286     FILE *fp = NULL;
287     int t, T;
288     int err = 0;
289 
290     T = gretl_bundle_get_int(b, "T", NULL);
291     S = gretl_bundle_get_array(b, "period", NULL);
292     x = gretl_bundle_get_matrix(b, "value", NULL);
293     if (T == 0 || S == NULL || x == NULL) {
294 	gretl_errmsg_set("dbnomics bundle is broken");
295 	err = E_DATA;
296     }
297 
298     if (!err) {
299 	tempname = gretl_make_dotpath("dbdata.XXXXXX");
300 	fp = gretl_mktemp(tempname, "wb");
301 	if (fp == NULL) {
302 	    err = E_FOPEN;
303 	}
304     }
305 
306     if (!err) {
307 	/* write temporary CSV file */
308 	gretl_push_c_numeric_locale();
309 	fprintf(fp, "obs,%s\n", vname);
310 	for (t=0; t<T; t++) {
311 	    obsstr = gretl_array_get_data(S, t);
312 	    if (na(x->val[t])) {
313 		fprintf(fp, "%s,NA\n", obsstr);
314 	    } else {
315 		fprintf(fp, "%s,%.15g\n", obsstr, x->val[t]);
316 	    }
317 	}
318 	fclose(fp);
319 	gretl_pop_c_numeric_locale();
320     }
321 
322     if (!err) {
323 	const char *vnames[] = {vname, NULL};
324 	const char *okey = "obs,%Y-%m-%d";
325 
326 	err = gretl_join_data(tempname,
327 			      vnames, 1,
328 			      dset,
329 			      NULL, /* ikeyvars */
330 			      okey, /* for daily data */
331 			      NULL, /* no filter */
332 			      NULL, /* no "dataname" */
333 			      0,    /* aggregation */
334 			      0,    /* seqval */
335 			      NULL, /* auxname */
336 			      NULL, /* tconvstr */
337 			      NULL, /* tconvfmt */
338 			      0,    /* midas_pd */
339 			      OPT_K, prn);
340     }
341 
342     if (err) {
343 	gui_errmsg(err);
344     } else {
345 	/* set series description and record command */
346 	const char *descrip;
347 	const char *prov, *dscode, *scode;
348 	int v;
349 
350 	descrip = gretl_bundle_get_string(b, "series_name", NULL);
351 	v = current_series_index(dset, vname);
352 	if (v > 0 && descrip != NULL) {
353 	    series_record_label(dset, v, descrip);
354 	}
355 	prov =   gretl_bundle_get_string(b, "provider_code", NULL);
356 	dscode = gretl_bundle_get_string(b, "dataset_code", NULL);
357 	scode =  gretl_bundle_get_string(b, "series_code", NULL);
358 	if (prov != NULL && dscode != NULL && scode != NULL) {
359 	    record_db_open_command(NULL);
360 	    lib_command_sprintf("series %s = dbnomics_fetch(\"%s/%s/%s\")",
361 				vname, prov, dscode, scode);
362 	    record_command_verbatim();
363 	}
364     }
365 
366     if (tempname != NULL) {
367 	gretl_remove(tempname);
368 	g_free(tempname);
369     }
370 
371     return err;
372 }
373 
374 /* end experimental */
375 
pd_conversion_check(DATASET * dbset,SERIESINFO * sinfo,windata_t * vwin)376 static int pd_conversion_check (DATASET *dbset,
377 				SERIESINFO *sinfo,
378 				windata_t *vwin)
379 {
380     int db_pd, err;
381 
382     db_pd = dbset != NULL ? dbset->pd : sinfo->pd;
383     err = check_db_import_conversion(db_pd, dataset);
384     if (err) {
385 	warnbox(_("Sorry, can't handle this frequency conversion"));
386     }
387 
388     return err;
389 }
390 
compact_method_string(CompactMethod method)391 static const char *compact_method_string (CompactMethod method)
392 {
393     if (method == COMPACT_SUM) {
394 	return "sum";
395     } else if (method == COMPACT_SOP) {
396 	return "first";
397     } else if (method == COMPACT_EOP) {
398 	return "last";
399     } else if (method == COMPACT_SPREAD) {
400 	return "spread";
401     } else {
402 	return NULL;
403     }
404 }
405 
trimmed_db_name(const char * fname)406 static const char *trimmed_db_name (const char *fname)
407 {
408     const char *s = fname;
409 
410     if (strstr(fname, gretl_binbase()) != NULL) {
411 	s = path_last_slash_const(fname);
412 	if (s != NULL) {
413 	    return s + 1;
414 	}
415     }
416 
417     return NULL;
418 }
419 
record_db_open_command(dbwrapper * dw)420 static void record_db_open_command (dbwrapper *dw)
421 {
422     const char *dbname = (dw == NULL)? "dbnomics" : dw->fname;
423     int dbtype = (dw == NULL)? GRETL_DBNOMICS : dw->dbtype;
424 
425     if (dbname != NULL) {
426 	const char *current_db = get_db_name();
427 	char *dbpath = NULL;
428 
429 	if (dbtype == GRETL_PCGIVE_DB) {
430 	    dbpath = g_strdup_printf("%s.bn7", dbname);
431 	} else if (dbtype == GRETL_NATIVE_DB) {
432 	    dbpath = g_strdup_printf("%s.bin", dbname);
433 	} else {
434 	    dbpath = g_strdup(dbname);
435 	}
436 
437 	/* record the "open" command if the database in
438 	   question is not already open */
439 
440 	if (strcmp(current_db, dbpath)) {
441 	    int err = set_db_name(dbpath, dbtype, NULL);
442 	    int done = 0;
443 
444 	    if (!err && dbtype == GRETL_NATIVE_DB) {
445 		const char *s = trimmed_db_name(dbpath);
446 
447 		if (s != NULL) {
448 		    lib_command_sprintf("open %s", s);
449 		    done = 1;
450 		}
451 	    }
452 
453 	    if (!err && !done) {
454 		if (dbtype == GRETL_NATIVE_DB_WWW) {
455 		    lib_command_sprintf("open %s --www", dbpath);
456 		} else if (strchr(dbpath, ' ') != NULL) {
457 		    lib_command_sprintf("open \"%s\"", dbpath);
458 		} else {
459 		    lib_command_sprintf("open %s", dbpath);
460 		}
461 	    }
462 
463 	    if (!err) {
464 		record_command_verbatim();
465 	    }
466 	}
467 
468 	g_free(dbpath);
469     }
470 }
471 
472 static char *dbnomics_id;
473 
set_dbnomics_id(const char * s)474 static void set_dbnomics_id (const char *s)
475 {
476     dbnomics_id = g_strdup(s);
477 }
478 
unset_dbnomics_id(void)479 static void unset_dbnomics_id (void)
480 {
481     free(dbnomics_id);
482     dbnomics_id = NULL;
483 }
484 
485 /* record successful importation in command log */
486 
record_db_import(const char * vname,int compact,CompactMethod method)487 static void record_db_import (const char *vname,
488 			      int compact,
489 			      CompactMethod method)
490 {
491     const char *cstr = NULL;
492 
493     if (dbnomics_id != NULL) {
494 	if (compact && (cstr = compact_method_string(method)) != NULL) {
495 	    lib_command_sprintf("data %s --name=%s --compact=%s",
496 				dbnomics_id, vname, cstr);
497 	} else {
498 	    lib_command_sprintf("data %s --name=%s", dbnomics_id, vname);
499 	}
500     } else {
501 	if (compact && (cstr = compact_method_string(method)) != NULL) {
502 	    lib_command_sprintf("data %s --compact=%s", vname,
503 				cstr);
504 	} else {
505 	    lib_command_sprintf("data %s", vname);
506 	}
507     }
508 
509     record_command_verbatim();
510 }
511 
handle_compact_spread(double ** dbZ,SERIESINFO * sinfo,DATASET * dset,DATASET * dbset)512 static int handle_compact_spread (double **dbZ,
513 				  SERIESINFO *sinfo,
514 				  DATASET *dset,
515 				  DATASET *dbset)
516 {
517     PRN *prn = NULL;
518     int err = 0;
519 
520     if (bufopen(&prn)) {
521 	return E_ALLOC;
522     }
523 
524     if (dbset != NULL) {
525 	err = lib_spread_dbnomics_data(dset, dbset, prn);
526     } else {
527 	err = lib_spread_db_data(dbZ, sinfo, dset, prn);
528     }
529 
530     if (err) {
531 	char *buf = gretl_print_steal_buffer(prn);
532 
533 	if (buf != NULL && *buf != '\0') {
534 	    errbox(buf);
535 	} else {
536 	    gui_errmsg(err);
537 	}
538     }
539 
540     gretl_print_destroy(prn);
541 
542     return err;
543 }
544 
maybe_retrieve_compact_method(int v,CompactMethod * pm)545 static void maybe_retrieve_compact_method (int v, CompactMethod *pm)
546 {
547     int m = series_get_compact_method(dataset, v);
548 
549     if (m != COMPACT_NONE) {
550 	*pm = m;
551     }
552 }
553 
554 static int
add_single_series_to_dataset(windata_t * vwin,DATASET * dbset)555 add_single_series_to_dataset (windata_t *vwin, DATASET *dbset)
556 {
557     CompactMethod cmethod = COMPACT_AVG;
558     int dbv, resp, overwrite = 0;
559     int compact = 0;
560     int expand = 0;
561     int err = 0;
562 
563     /* is there a series of this name already in the dataset? */
564     dbv = series_index(dataset, dbset->varname[1]);
565     if (dbv < dataset->v) {
566 	resp = yes_no_dialog("gretl",
567 			     _("There is already a variable of this name\n"
568 			       "in the dataset.  OK to overwrite it?"),
569 			     vwin_toplevel(vwin));
570 	if (resp != GRETL_YES) {
571 	    return 0;
572 	}
573 	overwrite = 1;
574 	maybe_retrieve_compact_method(dbv, &cmethod);
575     }
576 
577     if (vwin->role == VIEW_DBNOMICS) {
578 	if ((dbset->pd != dataset->pd) && dated_daily_data(dataset)
579 	    && (dbset->pd >= 5 && dbset->pd <= 7)) {
580 	    err = dbn_add_daily_data(vwin, dbset->varname[1],
581 				     dataset, NULL);
582 	    return err;
583 	}
584     }
585 
586     err = pd_conversion_check(dbset, NULL, vwin);
587     if (!err) {
588 	err = obs_overlap_check(dbset->pd, dbset->stobs, dbset->endobs,
589 				dbset->varname[1]);
590     }
591     if (err) {
592 	return err;
593     }
594 
595     record_db_open_command(NULL);
596 
597     if (dbset->pd < dataset->pd) {
598 	/* the incoming series needs to be expanded */
599 	resp = expand_data_dialog(1, 1, vwin->main);
600 	if (resp != GRETL_YES) {
601 	    return 0;
602 	} else {
603 	    expand = 1;
604 	}
605     } else if (dbset->pd > dataset->pd) {
606 	/* the incoming series needs to be compacted */
607 	data_compact_dialog(dbset->pd, &dataset->pd, NULL,
608 			    &cmethod, NULL, vwin->main);
609 	if (cmethod == COMPACT_NONE) {
610 	    return 0; /* canceled */
611 	} else if (cmethod == COMPACT_SPREAD) {
612 	    return handle_compact_spread(NULL, NULL, dataset, dbset);
613 	}
614 	compact = 1;
615     }
616 
617     if (!overwrite) {
618 	err = dataset_add_series(dataset, 1);
619 	if (err) {
620 	    nomem();
621 	    return err;
622 	}
623     }
624 
625     /* FIXME maybe handle tdisagg via post-processing of the
626        imported series? */
627 
628     err = transcribe_db_data(dataset, dbv, dbset->Z[1], dbset->pd,
629 			     dbset->n, dbset->stobs, cmethod);
630 
631     if (!err) {
632 	const char *vlabel = series_get_label(dbset, 1);
633 
634 	strcpy(dataset->varname[dbv], dbset->varname[1]);
635 	if (vlabel != NULL && *vlabel != '\0') {
636 	    series_set_label(dataset, dbv, vlabel);
637 	}
638 	record_db_import(dbset->varname[1], compact, cmethod);
639 	if (expand) {
640 	    series_set_orig_pd(dataset, dbv, dbset->pd);
641 	}
642     } else {
643 	if (!overwrite) {
644 	    dataset_drop_last_variables(dataset, 1);
645 	}
646 	gui_errmsg(err);
647     }
648 
649     if (!err && expand) {
650 	give_tdisagg_option(dbv);
651     }
652 
653     return err;
654 }
655 
656 /* multiple series version of data adding function */
657 
658 static int
add_db_series_to_dataset(windata_t * vwin,DATASET * dbset,dbwrapper * dw)659 add_db_series_to_dataset (windata_t *vwin, DATASET *dbset, dbwrapper *dw)
660 {
661     SERIESINFO *sinfo;
662     double **dbZ = dbset->Z;
663     CompactMethod cmethod = COMPACT_AVG;
664     int resp, chosen = 0;
665     int nx, vx = 0;
666     int i, err = 0;
667 
668     sinfo = &dw->sinfo[0];
669     err = pd_conversion_check(NULL, sinfo, vwin);
670     if (err) {
671 	return err;
672     }
673 
674     record_db_open_command(dw);
675 
676     nx = 0;
677     for (i=0; i<dw->nv && !err; i++) {
678 	if (dw->sinfo[i].pd < dataset->pd) {
679 	    nx++;
680 	}
681     }
682     if (nx > 0) {
683 	resp = expand_data_dialog(nx, dw->nv, vwin->main);
684 	if (resp != GRETL_YES) {
685 	    return 0;
686 	}
687     }
688 
689     for (i=0; i<dw->nv && !err; i++) {
690 	int v, dbv;
691 	int existing = 0;
692 	int overwrite = 0;
693 	int compact = 0;
694 	int expand = 0;
695 
696 	sinfo = &dw->sinfo[i];
697 	v = sinfo->v;
698 
699 	if (obs_overlap_check(sinfo->pd, sinfo->stobs, sinfo->endobs,
700 			      sinfo->varname)) {
701 	    continue;
702 	}
703 
704 	dbv = series_index(dataset, sinfo->varname);
705 	if (dbv < dataset->v) {
706 	    existing = 1;
707 	    maybe_retrieve_compact_method(dbv, &cmethod);
708 	}
709 
710 	if (sinfo->pd < dataset->pd) {
711 	    /* the incoming series needs to be expanded */
712 	    expand = 1;
713 	} else if (sinfo->pd > dataset->pd) {
714 	    /* the incoming series needs to be compacted */
715 	    if (!chosen) {
716 		data_compact_dialog(sinfo->pd, &dataset->pd, NULL,
717 				    &cmethod, NULL, vwin->main);
718 		if (cmethod == COMPACT_NONE) {
719 		    /* canceled */
720 		    return 0;
721 		}
722 		chosen = 1;
723 	    }
724 	    compact = 1;
725 	    if (cmethod == COMPACT_SPREAD) {
726 		err = handle_compact_spread(dbZ, sinfo, dataset, NULL);
727 		dbZ += 1; /* advance actual data pointer */
728 		if (err) {
729 		    break;
730 		} else {
731 		    record_db_import(sinfo->varname, compact, cmethod);
732 		    continue;
733 		}
734 	    }
735 	}
736 
737 	if (existing) {
738 	    if (dw->nv == 1) {
739 		resp = yes_no_dialog("gretl",
740 				     _("There is already a variable of this name\n"
741 				       "in the dataset.  OK to overwrite it?"),
742 				     vwin_toplevel(vwin));
743 		if (resp != GRETL_YES) {
744 		    return 0;
745 		}
746 	    }
747 	    overwrite = 1;
748 	}
749 
750 	if (!overwrite) {
751 	    err = dataset_add_series(dataset, 1);
752 	    if (err) {
753 		nomem();
754 		return err;
755 	    }
756 	}
757 
758 	err = transcribe_db_data(dataset, dbv, dbZ[v], sinfo->pd,
759 				 sinfo->nobs, sinfo->stobs, cmethod);
760 	if (err) {
761 	    gui_errmsg(err);
762 	    if (!overwrite) {
763 		dataset_drop_last_variables(dataset, 1);
764 	    }
765 	} else {
766 	    strcpy(dataset->varname[dbv], sinfo->varname);
767 	    series_set_label(dataset, dbv, sinfo->descrip);
768 	    if (expand) {
769 		series_set_orig_pd(dataset, dbv, sinfo->pd);
770 		if (nx == 1) vx = dbv;
771 	    }
772 	    record_db_import(sinfo->varname, compact, cmethod);
773 	}
774     }
775 
776     if (!err && vx > 0) {
777 	give_tdisagg_option(vx);
778     }
779 
780     return err;
781 }
782 
add_dbdata(windata_t * vwin,DATASET * dbset,dbwrapper * dw,int * freeit)783 static void add_dbdata (windata_t *vwin, DATASET *dbset,
784 			dbwrapper *dw, int *freeit)
785 {
786     SERIESINFO *sinfo = NULL;
787     int i, err = 0;
788 
789     if (data_status) {
790 	/* we already have data in gretl's workspace */
791 	if (dw != NULL) {
792 	    add_db_series_to_dataset(vwin, dbset, dw);
793 	} else {
794 	    add_single_series_to_dataset(vwin, dbset);
795 	}
796     } else {
797 	/* no data open: start new data set from db */
798 	destroy_dataset(dataset);
799 	dataset = dbset;
800 	*freeit = 0;
801 
802 	if (dw != NULL) {
803 	    record_db_open_command(dw);
804 	    for (i=1; i<=dw->nv && !err; i++) {
805 		sinfo = &dw->sinfo[i-1];
806 		strcpy(dataset->varname[i], sinfo->varname);
807 		series_set_label(dataset, i, sinfo->descrip);
808 		lib_command_sprintf("data %s", sinfo->varname);
809 		record_command_verbatim();
810 	    }
811 	} else {
812 	    record_db_open_command(NULL);
813 	    record_db_import(dbset->varname[1], 0, 0);
814 	}
815 	data_status |= (GUI_DATA | MODIFIED_DATA);
816     }
817 
818     if (!err) {
819 	register_data(DATA_APPENDED);
820     }
821 }
822 
db_display_series(GtkWidget * w,windata_t * vwin)823 static void db_display_series (GtkWidget *w, windata_t *vwin)
824 {
825     gui_get_db_series(vwin, DB_DISPLAY);
826 }
827 
db_graph_series(GtkWidget * w,windata_t * vwin)828 static void db_graph_series (GtkWidget *w, windata_t *vwin)
829 {
830     gui_get_db_series(vwin, DB_GRAPH);
831 }
832 
db_import_series(GtkWidget * w,windata_t * vwin)833 static void db_import_series (GtkWidget *w, windata_t *vwin)
834 {
835     gui_get_db_series(vwin, DB_IMPORT);
836 }
837 
sync_db_windows(void)838 void sync_db_windows (void)
839 {
840     const char *dname = get_db_name();
841 
842     if (*dname != '\0') {
843 	windata_t *vwin = get_browser_for_gretl_database(dname);
844 
845 	if (vwin != NULL) {
846 	    add_local_db_series_list(vwin);
847 	}
848     }
849 }
850 
db_delete_callback(GtkWidget * w,windata_t * vwin)851 static void db_delete_callback (GtkWidget *w, windata_t *vwin)
852 {
853     int *list = db_get_selection_list(vwin);
854     gchar *query;
855     int resp, err = 0;
856 
857     if (list == NULL) {
858 	return;
859     }
860 
861     query = g_strdup_printf(_("Really delete the selected series\n"
862 			      "from the database '%s'?"),
863 			    gtk_window_get_title(GTK_WINDOW(vwin->main)));
864 
865     resp = yes_no_dialog("gretl", query, vwin_toplevel(vwin));
866 
867     g_free(query);
868 
869     if (resp == GRETL_YES) {
870 	err = db_delete_series_by_number(list, vwin->fname);
871 	if (err) {
872 	    gui_errmsg(err);
873 	} else {
874 	    /* revise window contents */
875 	    add_local_db_series_list(vwin);
876 	}
877     }
878 }
879 
880 /* this pointer to the source "vwin" for drag-and-drop is
881    set by drag selection callback, do_db_drag()
882 */
883 static windata_t *vwin_drag_src;
884 
885 /* import series from a database window into main
886    gretl workspace */
887 
drag_import_db_series(void)888 void drag_import_db_series (void)
889 {
890     windata_t *vwin = vwin_drag_src;
891 
892     if (vwin != NULL) {
893 	gui_get_db_series(vwin, DB_IMPORT);
894 	vwin_drag_src = NULL;
895     }
896 }
897 
diffdate(double d1,double d0,int pd)898 static int diffdate (double d1, double d0, int pd)
899 {
900     double x;
901 
902     if (pd == 4 || pd == 12) {
903 	char s[16];
904 	int maj, min;
905 	int dmaj, dmin;
906 
907 	gretl_push_c_numeric_locale();
908 
909 	sprintf(s, "%g", d1);
910 	sscanf(s, "%d.%d", &dmaj, &dmin);
911 
912 	sprintf(s, "%g", d0);
913 	sscanf(s, "%d.%d", &maj, &min);
914 
915 	gretl_pop_c_numeric_locale();
916 
917 	dmaj -= maj;
918 	dmin -= min;
919 
920 	x = dmaj * pd + dmin;
921     } else {
922 	x = d1 - d0;
923     }
924 
925     return x;
926 }
927 
dataset_from_dbwrapper(dbwrapper * dw)928 static DATASET *dataset_from_dbwrapper (dbwrapper *dw)
929 {
930     DATASET *dset = NULL;
931     SERIESINFO *sinfo;
932     char stobs[OBSLEN], endobs[OBSLEN];
933     double xd, xdmax = 0, xdmin = DBL_MAX;
934     int n0 = 0, nmax = 0;
935     int i;
936 
937     /* Here we construct a dataset which can accommodate all
938        the seleted series (in case there's more than one).
939        Note that while multiple selection is enabled in a
940        database window we have made it impossible to compose
941        a selection that includes series of differing
942        frequencies (i.e. they must all be quarterly, all
943        annual, or whatever).
944     */
945 
946     for (i=0; i<dw->nv; i++) {
947 	sinfo = &dw->sinfo[i];
948 	xd = get_date_x(sinfo->pd, sinfo->stobs);
949 	fprintf(stderr, "var %d: nobs=%d, pd=%d, stobs='%s', sd0=%g\n",
950 		i, sinfo->nobs, sinfo->pd, sinfo->stobs, xd);
951 	if (xd < xdmin) {
952 	    strcpy(stobs, sinfo->stobs);
953 	    xdmin = xd;
954 	    if (sinfo->nobs > n0) {
955 		n0 = sinfo->nobs;
956 	    }
957 	}
958 	if (xd > xdmax) {
959 	    strcpy(endobs, sinfo->endobs);
960 	    xdmax = xd;
961 	}
962 	if (sinfo->nobs > nmax) {
963 	    nmax = sinfo->nobs;
964 	}
965 	sinfo->v = i + 1;
966 	sinfo->t2 = sinfo->nobs - 1;
967     }
968 
969     if (xdmax > xdmin) {
970 	int ni, dd;
971 
972 	for (i=0; i<dw->nv; i++) {
973 	    sinfo = &dw->sinfo[i];
974 	    ni = sinfo->nobs;
975 	    xd = get_date_x(sinfo->pd, sinfo->stobs);
976 	    if (xd > xdmin) {
977 		dd = diffdate(xd, xdmin, sinfo->pd);
978 		ni += dd;
979 		sinfo->t1 = dd;
980 		sinfo->t2 += dd;
981 	    }
982 	    if (ni > nmax) {
983 		nmax = ni;
984 	    }
985 	}
986     }
987 
988     fprintf(stderr, "min(sd0) = %g, stobs='%s', n = %d\n", xdmin,
989 	    stobs, nmax);
990 
991     dset = create_new_dataset(dw->nv + 1, nmax, 0);
992 
993     if (dset != NULL) {
994 	dset->pd = dw->sinfo[0].pd;
995 	strcpy(dset->stobs, stobs);
996 	strcpy(dset->endobs, endobs);
997 	colonize_obs(dset->stobs);
998 	colonize_obs(dset->endobs);
999 	dset->sd0 = xdmin;
1000 	set_time_series(dset);
1001     }
1002 
1003     return dset;
1004 }
1005 
gui_get_db_series(windata_t * vwin,int cmd)1006 static void gui_get_db_series (windata_t *vwin, int cmd)
1007 {
1008     int dbcode = vwin->role;
1009     DATASET *dbset = NULL;
1010     dbwrapper *dw;
1011     int freeit = 1;
1012     int i, err = 0;
1013 
1014     /* build wrapper for selected row(s) of @vwin */
1015     dw = get_db_series_info(vwin, dbcode);
1016     if (dw == NULL) {
1017 	return;
1018     }
1019 
1020     /* build "superset" dataset, allowing multiple selection */
1021     dbset = dataset_from_dbwrapper(dw);
1022     if (dbset == NULL) {
1023 	dbwrapper_destroy(dw);
1024 	nomem();
1025 	return;
1026     }
1027 
1028     for (i=0; i<dw->nv; i++) {
1029 	SERIESINFO *sinfo = &dw->sinfo[i];
1030 
1031 	if (dbcode == NATIVE_SERIES) {
1032 	    err = get_native_db_data(vwin->fname, sinfo, dbset->Z);
1033 	} else if (dbcode == REMOTE_SERIES) {
1034 	    err = gui_get_remote_db_data(vwin, sinfo, dbset->Z);
1035 	} else if (dbcode == RATS_SERIES) {
1036 	    err = get_rats_db_data(vwin->fname, sinfo, dbset->Z);
1037 	} else if (dbcode == PCGIVE_SERIES) {
1038 	    err = get_pcgive_db_data(vwin->fname, sinfo, dbset->Z);
1039 	}
1040 
1041 	if (cmd == DB_IMPORT && err == DB_MISSING_DATA) {
1042 	    warnbox(_("Warning: series has missing observations"));
1043 	}
1044 
1045 	if (err && err != DB_MISSING_DATA && dbcode != REMOTE_SERIES) {
1046 	    errbox(_("Couldn't access binary datafile"));
1047 	    goto bailout;
1048 	}
1049 
1050 	strcpy(dbset->varname[i+1], sinfo->varname);
1051 	series_set_label(dbset, i+1, sinfo->descrip);
1052     }
1053 
1054     if (cmd == DB_DISPLAY) {
1055 	display_dbdata(dbset);
1056     } else if (cmd == DB_GRAPH) {
1057 	graph_dbdata(dbset);
1058     } else if (cmd == DB_IMPORT) {
1059 	add_dbdata(vwin, dbset, dw, &freeit);
1060     }
1061 
1062  bailout:
1063 
1064     if (freeit) {
1065 	destroy_dataset(dbset);
1066     }
1067 
1068     dbwrapper_destroy(dw);
1069 }
1070 
1071 /* double-click callback */
1072 
display_db_series(windata_t * vwin)1073 void display_db_series (windata_t *vwin)
1074 {
1075     gui_get_db_series(vwin, DB_DISPLAY);
1076 }
1077 
db_view_codebook(GtkWidget * w,windata_t * vwin)1078 static void db_view_codebook (GtkWidget *w, windata_t *vwin)
1079 {
1080     gchar *cbname;
1081 
1082     if (vwin->flags & VWIN_CB_PDF) {
1083 	cbname = g_strdup_printf("%s.pdf", vwin->fname);
1084 	gretl_show_pdf(cbname, NULL);
1085     } else {
1086 	cbname = g_strdup_printf("%s.cb", vwin->fname);
1087 	view_file(cbname, 0, 0, 78, 350, VIEW_CODEBOOK);
1088     }
1089 
1090     g_free(cbname);
1091 }
1092 
db_show_index(GtkWidget * w,windata_t * vwin)1093 static void db_show_index (GtkWidget *w, windata_t *vwin)
1094 {
1095     show_native_dbs();
1096 }
1097 
build_db_content_popup(windata_t * vwin,int cb,int del)1098 static void build_db_content_popup (windata_t *vwin, int cb, int del)
1099 {
1100     if (vwin->popup != NULL) {
1101 	return;
1102     }
1103 
1104     vwin->popup = gtk_menu_new();
1105 
1106     add_popup_item(_("Display"), vwin->popup,
1107 		   G_CALLBACK(db_display_series),
1108 		   vwin);
1109     add_popup_item(_("Graph"), vwin->popup,
1110 		   G_CALLBACK(db_graph_series),
1111 		   vwin);
1112     add_popup_item(_("Import"), vwin->popup,
1113 		   G_CALLBACK(db_import_series),
1114 		   vwin);
1115     if (del) {
1116 	add_popup_item(_("Delete"), vwin->popup,
1117 		       G_CALLBACK(db_delete_callback),
1118 		       vwin);
1119     }
1120 
1121     if (cb) {
1122 	add_popup_item(_("Codebook"), vwin->popup,
1123 		       G_CALLBACK(db_view_codebook),
1124 		       vwin);
1125     }
1126 }
1127 
1128 enum {
1129     DEL_BTN = 1,
1130     CB_BTN,
1131     IDX_BTN
1132 };
1133 
1134 static GretlToolItem db_items[] = {
1135     { N_("Display values"), GTK_STOCK_MEDIA_PLAY, G_CALLBACK(db_display_series), 0 },
1136     { N_("Graph"),          GRETL_STOCK_TS,   G_CALLBACK(db_graph_series), 0 },
1137     { N_("Add to dataset"), GTK_STOCK_ADD,    G_CALLBACK(db_import_series), 0 },
1138     { N_("List databases"), GTK_STOCK_INDEX,  G_CALLBACK(db_show_index), IDX_BTN },
1139     { N_("Delete"),         GTK_STOCK_DELETE, G_CALLBACK(db_delete_callback), DEL_BTN },
1140     { N_("Codebook"),       GRETL_STOCK_BOOK, G_CALLBACK(db_view_codebook), CB_BTN }
1141 };
1142 
1143 static int n_db_items = G_N_ELEMENTS(db_items);
1144 
make_db_toolbar(windata_t * vwin,int cb,int del,int index_button)1145 static void make_db_toolbar (windata_t *vwin, int cb, int del,
1146 			     int index_button)
1147 {
1148     GtkWidget *hbox;
1149     GretlToolItem *item;
1150     int i;
1151 
1152     hbox = gtk_hbox_new(FALSE, 0);
1153     gtk_box_pack_start(GTK_BOX(vwin->vbox), hbox, FALSE, FALSE, 0);
1154 
1155     vwin->mbar = gretl_toolbar_new(NULL);
1156 
1157     for (i=0; i<n_db_items; i++) {
1158 	item = &db_items[i];
1159 	if (!del && item->flag == DEL_BTN) {
1160 	    continue;
1161 	} else if (!cb && item->flag == CB_BTN) {
1162 	    continue;
1163 	} else if (!index_button && item->flag == IDX_BTN) {
1164 	    continue;
1165 	}
1166 	gretl_toolbar_insert(vwin->mbar, item, item->func, vwin, -1);
1167     }
1168 
1169     gtk_box_pack_start(GTK_BOX(hbox), vwin->mbar, FALSE, FALSE, 0);
1170     vwin_add_winlist(vwin);
1171     vwin_add_finder(vwin);
1172     gtk_widget_show_all(hbox);
1173 }
1174 
db_has_codebook(const char * fname)1175 static int db_has_codebook (const char *fname)
1176 {
1177     gchar *testname;
1178     int err, ret = CB_NONE;
1179 
1180     /* try first for *.cb (plain text) file */
1181     testname = g_strdup_printf("%s.cb", fname);
1182     err = gretl_test_fopen(testname, "rb");
1183     if (err == 0) {
1184 	ret = CB_TEXT;
1185     } else {
1186 	/* try for PDF documentation? */
1187 	g_free(testname);
1188 	testname = g_strdup_printf("%s.pdf", fname);
1189 	err = gretl_test_fopen(testname, "rb");
1190 	if (err == 0) {
1191 	    ret = CB_PDF;
1192 	}
1193     }
1194 
1195     g_free(testname);
1196 
1197     return ret;
1198 }
1199 
db_is_writable(int action,const char * fname)1200 static int db_is_writable (int action, const char *fname)
1201 {
1202     int ret = 0;
1203 
1204     if (action == NATIVE_SERIES) {
1205 	char testname[MAXLEN];
1206 	int err;
1207 
1208 	strcpy(testname, fname);
1209 	strcat(testname, ".bin");
1210 	err = gretl_write_access(testname);
1211 	if (!err) {
1212 	    ret = 1;
1213 	}
1214     }
1215 
1216     return ret;
1217 }
1218 
1219 static gboolean
db_col_callback(GtkWidget * w,GdkEventMotion * event,gpointer p)1220 db_col_callback (GtkWidget *w, GdkEventMotion *event, gpointer p)
1221 {
1222     GtkTreeViewColumn *col =
1223 	gtk_tree_view_get_column(GTK_TREE_VIEW(w), 1);
1224 
1225     if (gtk_tree_view_column_get_max_width(col) > 0) {
1226 	/* remove the width constraint */
1227 	gtk_tree_view_column_set_max_width(col, -1);
1228     }
1229 
1230     return 0;
1231 }
1232 
1233 static void
maybe_adjust_descrip_column(windata_t * vwin)1234 maybe_adjust_descrip_column (windata_t *vwin)
1235 {
1236     GtkTreeViewColumn *col;
1237     GdkWindow *window;
1238     gint w0, w1, lw, w1max;
1239 
1240     col = gtk_tree_view_get_column(GTK_TREE_VIEW(vwin->listbox), DBCOL_VARNAME);
1241     w0 = gtk_tree_view_column_get_width(col);
1242 
1243     col = gtk_tree_view_get_column(GTK_TREE_VIEW(vwin->listbox), DBCOL_DESCRIP);
1244     w1 = gtk_tree_view_column_get_width(col);
1245 
1246     window = gtk_widget_get_window(vwin->listbox);
1247 
1248 #if GTK_MAJOR_VERSION >= 3
1249     lw = gdk_window_get_width(window);
1250 #else
1251     gdk_drawable_get_size(window, &lw, NULL);
1252 #endif
1253 
1254     w1max = lw - w0 - 140;
1255 
1256     if (w1 > w1max) {
1257 	gtk_tree_view_column_set_max_width(col, w1max);
1258 	g_signal_connect(vwin->listbox, "motion-notify-event",
1259 			 G_CALLBACK(db_col_callback), NULL);
1260     }
1261 }
1262 
1263 static int
make_db_index_window(int action,char * fname,char * buf,int index_button)1264 make_db_index_window (int action, char *fname, char *buf,
1265 		      int index_button)
1266 {
1267     GtkWidget *listbox;
1268     gchar *title;
1269     windata_t *vwin;
1270     int db_width = 700, db_height = 420;
1271     int cb = 0, del = 0;
1272     int err = 0;
1273 
1274     vwin = get_browser_for_database(fname);
1275 
1276     if (vwin != NULL) {
1277 	gtk_window_present(GTK_WINDOW(vwin->main));
1278 	return 0;
1279     }
1280 
1281     if (action == REMOTE_SERIES && buf == NULL) {
1282 	return 1;
1283     }
1284 
1285     if (buf == NULL && strrslash(fname) != NULL) {
1286 	title = strrslash(fname) + 1;
1287     } else {
1288 	title = fname;
1289     }
1290 
1291     vwin = gretl_browser_new(action, title);
1292     if (vwin == NULL) {
1293 	return 1;
1294     }
1295 
1296     db_width *= gui_scale;
1297     db_height *= gui_scale;
1298     gtk_window_set_default_size(GTK_WINDOW(vwin->main), db_width, db_height);
1299 
1300     if (action == NATIVE_SERIES || action == PCGIVE_SERIES) {
1301 	strip_extension(fname);
1302     }
1303 
1304     strcpy(vwin->fname, fname);
1305 
1306     vwin->vbox = gtk_vbox_new(FALSE, 1);
1307     gtk_box_set_spacing(GTK_BOX(vwin->vbox), 4);
1308     gtk_container_set_border_width(GTK_CONTAINER(vwin->vbox), 4);
1309     gtk_container_add(GTK_CONTAINER(vwin->main), vwin->vbox);
1310 
1311     cb = db_has_codebook(fname);
1312     del = db_is_writable(action, fname);
1313 
1314     if (cb == CB_PDF) {
1315 	vwin->flags |= VWIN_CB_PDF;
1316     }
1317 
1318     make_db_toolbar(vwin, cb, del, index_button);
1319     build_db_content_popup(vwin, cb, del);
1320 
1321     listbox = database_window(vwin);
1322     gtk_box_pack_start(GTK_BOX(vwin->vbox), listbox, TRUE, TRUE, 0);
1323 
1324     if (action == REMOTE_SERIES) {
1325 	GtkWidget *hbox;
1326 
1327 	hbox = gtk_hbox_new(FALSE, 0);
1328 	gtk_box_pack_start(GTK_BOX(vwin->vbox), hbox, FALSE, FALSE, 0);
1329 	vwin->status = gtk_label_new(_("Network status: OK"));
1330 	gtk_label_set_justify(GTK_LABEL(vwin->status), GTK_JUSTIFY_LEFT);
1331 	gtk_box_pack_start(GTK_BOX(hbox), vwin->status, FALSE, FALSE, 0);
1332     }
1333 
1334     if (action == NATIVE_SERIES) {
1335 	err = add_local_db_series_list(vwin);
1336     } else if (action == REMOTE_SERIES) {
1337 	err = add_remote_db_series_list(vwin, buf);
1338     } else if (action == RATS_SERIES) {
1339 	err = add_rats_db_series_list(vwin);
1340     } else if (action == PCGIVE_SERIES) {
1341 	err = add_pcgive_db_series_list(vwin);
1342     }
1343 
1344     if (err) {
1345 	gtk_widget_destroy(vwin->main);
1346     } else {
1347 	gtk_widget_show_all(vwin->main);
1348 	maybe_adjust_descrip_column(vwin);
1349 	listbox_select_first(vwin);
1350     }
1351 
1352     return err;
1353 }
1354 
open_rats_window(char * fname)1355 void open_rats_window (char *fname)
1356 {
1357     make_db_index_window(RATS_SERIES, fname, NULL, 0);
1358 }
1359 
open_bn7_window(char * fname)1360 void open_bn7_window (char *fname)
1361 {
1362     make_db_index_window(PCGIVE_SERIES, fname, NULL, 0);
1363 }
1364 
check_serinfo(char * str,char * sername,int * nobs)1365 static int check_serinfo (char *str, char *sername, int *nobs)
1366 {
1367     char stobs[OBSLEN], endobs[OBSLEN];
1368     char pdc = 0;
1369     int err = 0;
1370 
1371     *stobs = *endobs = '\0';
1372     *nobs = 0;
1373 
1374     if (!isalpha((unsigned char) *sername) ||
1375 	sscanf(str, "%c %10s - %10s %*s = %d",
1376 	       &pdc, stobs, endobs, nobs) != 4 ||
1377 	!isdigit((unsigned char) *stobs) ||
1378 	!isdigit((unsigned char) *endobs) ||
1379 	(pdc != 'M' && pdc != 'A' && pdc != 'Q' && pdc != 'U' &&
1380 	 pdc != 'D' && pdc != 'B' && pdc != 'S')) {
1381 	errbox_printf(_("Database parse error at variable '%s'"), sername);
1382 	fprintf(stderr, "%s: stobs='%s', endobs='%s', pdc='%c', nobs = %d\n",
1383 		sername, stobs, endobs, pdc, *nobs);
1384 	err = 1;
1385     }
1386 
1387     return err;
1388 }
1389 
start_trim(char * s)1390 static char *start_trim (char *s)
1391 {
1392     while (*s == ' ') s++;
1393 
1394     return s;
1395 }
1396 
do_db_drag(GtkWidget * w,GdkDragContext * context,GtkSelectionData * sel,guint info,guint t,windata_t * vwin)1397 static void do_db_drag (GtkWidget *w, GdkDragContext *context,
1398 			GtkSelectionData *sel, guint info, guint t,
1399 			windata_t *vwin)
1400 {
1401     vwin_drag_src = vwin;
1402     gtk_selection_data_set(sel, GDK_SELECTION_TYPE_INTEGER, 8,
1403 			   (const guchar *) &vwin, sizeof vwin);
1404 }
1405 
db_drag_connect(windata_t * vwin,int i)1406 static void db_drag_connect (windata_t *vwin, int i)
1407 {
1408     gtk_drag_source_set(vwin->listbox, GDK_BUTTON1_MASK,
1409 			&gretl_drag_targets[i],
1410 			1, GDK_ACTION_COPY);
1411     g_signal_connect(G_OBJECT(vwin->listbox), "drag-data-get",
1412 		     G_CALLBACK(do_db_drag),
1413 		     vwin);
1414 }
1415 
1416 #define DB_LINELEN 512
1417 
add_local_db_series_list(windata_t * vwin)1418 static int add_local_db_series_list (windata_t *vwin)
1419 {
1420     GtkListStore *store;
1421     GtkTreeIter iter;
1422     gchar *row[3];
1423     char sername[VNAMELEN];
1424     char line1[DB_LINELEN], line2[128];
1425     char dbidx[MAXLEN];
1426     FILE *fp;
1427     size_t n;
1428     int offset = 0;
1429     int err = 0;
1430 
1431     strcpy(dbidx, vwin->fname);
1432     strcat(dbidx, ".idx");
1433     fp = gretl_fopen(dbidx, "r");
1434 
1435     if (fp == NULL) {
1436 	file_read_errbox(dbidx);
1437 	return 1;
1438     }
1439 
1440     store = GTK_LIST_STORE(gtk_tree_view_get_model
1441 			   (GTK_TREE_VIEW(vwin->listbox)));
1442     gtk_list_store_clear(store);
1443     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1444 
1445     while (fgets(line1, sizeof line1, fp) != NULL && !err) {
1446 	int len, nobs = 0;
1447 
1448 	if (*line1 == '#') {
1449 	    continue;
1450 	}
1451 
1452 	len = strlen(line1);
1453 	if (line1[len-1] != '\n') {
1454 	    errbox_printf("Database index line is too long: max is %d characters",
1455 			  DB_LINELEN - 1);
1456 	    break;
1457 	}
1458 
1459 	err = utf8_correct(line1);
1460 
1461 	tailstrip(line1);
1462 	gretl_charsub(line1, '\t', ' ');
1463 
1464 	if (gretl_scan_varname(line1, sername) != 1) {
1465 	    break;
1466 	}
1467 
1468 	n = strlen(sername);
1469 	row[0] = sername;
1470 	row[1] = start_trim(line1 + n + 1);
1471 
1472 	if (fgets(line2, sizeof line2, fp) == NULL) {
1473 	    break;
1474 	}
1475 
1476 	tailstrip(line2);
1477 	row[2] = line2;
1478 
1479 	if (!err) {
1480 	    err = check_serinfo(line2, sername, &nobs);
1481 	}
1482 
1483 	gtk_list_store_append(store, &iter);
1484 	gtk_list_store_set(store, &iter,
1485 			   DBCOL_VARNAME, row[0],
1486 			   DBCOL_DESCRIP, row[1],
1487 			   DBCOL_OBSINFO, row[2],
1488 			   DBCOL_OFFSET,  offset * sizeof(dbnumber),
1489 			   -1);
1490 
1491 	offset += nobs;
1492     }
1493 
1494     fclose(fp);
1495     db_drag_connect(vwin, GRETL_DBSERIES_PTR);
1496 
1497     return 0;
1498 }
1499 
add_remote_db_series_list(windata_t * vwin,char * buf)1500 static int add_remote_db_series_list (windata_t *vwin, char *buf)
1501 {
1502     GtkListStore *store;
1503     GtkTreeIter iter;
1504     gchar *row[3];
1505     char sername[VNAMELEN];
1506     char line1[256], line2[256];
1507     int offset = 0;
1508     int n, err = 0;
1509 
1510     store = GTK_LIST_STORE(gtk_tree_view_get_model
1511 			   (GTK_TREE_VIEW(vwin->listbox)));
1512     gtk_list_store_clear(store);
1513     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1514 
1515     bufgets_init(buf);
1516 
1517     while (bufgets(line1, sizeof line1, buf) && !err) {
1518 	int nobs = 0;
1519 
1520 	if (*line1 == '#') {
1521 	    continue;
1522 	}
1523 	tailstrip(line1);
1524 	gretl_charsub(line1, '\t', ' ');
1525 	err = utf8_correct(line1);
1526 	if (gretl_scan_varname(line1, sername) != 1) {
1527 	    break;
1528 	}
1529 
1530 	n = strlen(sername);
1531 	row[0] = sername;
1532 	row[1] = start_trim(line1 + n + 1);
1533 
1534 	if (bufgets(line2, sizeof line2, buf) == NULL) {
1535 	    break;
1536 	}
1537 
1538 	row[2] = tailstrip(line2);
1539 	if (!err) {
1540 	    err = check_serinfo(line2, sername, &nobs);
1541 	}
1542 
1543 	gtk_list_store_append(store, &iter);
1544 	gtk_list_store_set (store, &iter,
1545 			    DBCOL_VARNAME, row[0],
1546 			    DBCOL_DESCRIP, row[1],
1547 			    DBCOL_OBSINFO, row[2],
1548 			    DBCOL_OFFSET, nobs * sizeof(dbnumber),
1549 			    -1);
1550 
1551 	offset += nobs;
1552     }
1553 
1554     bufgets_finalize(buf);
1555     db_drag_connect(vwin, GRETL_DBSERIES_PTR);
1556 
1557     return 0;
1558 }
1559 
iso_comment_to_utf8(const gchar * src,int * err)1560 static gchar *iso_comment_to_utf8 (const gchar *src, int *err)
1561 {
1562     gchar *conv = NULL;
1563 
1564     if (!g_utf8_validate(src, -1, NULL)) {
1565 	GError *gerr = NULL;
1566 	gsize wrote;
1567 
1568 	conv = g_convert(src, -1,
1569 			 "UTF-8",
1570 			 "ISO-8859-1",
1571 			 NULL, &wrote, &gerr);
1572 
1573 	if (gerr != NULL) {
1574 	    if (err != NULL) {
1575 		errbox(gerr->message);
1576 		*err = 1;
1577 	    }
1578 	    g_error_free(gerr);
1579 	}
1580     } else {
1581 	conv = g_strdup(src);
1582     }
1583 
1584     return conv;
1585 }
1586 
format_obs_info(SERIESINFO * sinfo)1587 static gchar *format_obs_info (SERIESINFO *sinfo)
1588 {
1589     int pdc = '1';
1590 
1591     if (sinfo->pd == 4) {
1592 	pdc = 'Q';
1593     } else if (sinfo->pd == 12) {
1594 	pdc = 'M';
1595     } else if (sinfo->pd == 5) {
1596 	pdc = 'B';
1597     } else if (sinfo->pd == 6) {
1598 	pdc = 'S';
1599     } else if (sinfo->pd == 7) {
1600 	pdc = 'D';
1601     } else if (sinfo->pd == 52) {
1602 	pdc = 'W';
1603     }
1604 
1605     return g_strdup_printf("%c  %s - %s  n = %d", pdc,
1606 			   sinfo->stobs, sinfo->endobs,
1607 			   sinfo->nobs);
1608 }
1609 
insert_and_free_dbwrapper(dbwrapper * dw,GtkWidget * w)1610 static void insert_and_free_dbwrapper (dbwrapper *dw, GtkWidget *w)
1611 {
1612     GtkTreeView *view = GTK_TREE_VIEW(w);
1613     GtkListStore *store;
1614     GtkTreeIter iter;
1615     int i, err = 0;
1616     int *perr = &err;
1617 
1618     store = GTK_LIST_STORE(gtk_tree_view_get_model(view));
1619     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1620 
1621     for (i=0; i<dw->nv; i++) {
1622 	gchar *obsinfo;
1623 
1624 	gtk_list_store_append(store, &iter);
1625 	gtk_list_store_set(store, &iter, DBCOL_VARNAME,
1626 			   dw->sinfo[i].varname, -1);
1627 
1628 	if (*dw->sinfo[i].descrip != 0) {
1629 	    gchar *comment;
1630 
1631 	    comment = iso_comment_to_utf8(dw->sinfo[i].descrip, perr);
1632 	    if (perr != NULL && *perr) {
1633 		/* don't keep displaying error messages */
1634 		perr = NULL;
1635 	    }
1636 	    if (comment != NULL) {
1637 		gtk_list_store_set(store, &iter, DBCOL_DESCRIP,
1638 				   comment, -1);
1639 		g_free(comment);
1640 	    }
1641 	}
1642 
1643 	obsinfo = format_obs_info(&dw->sinfo[i]);
1644 	gtk_list_store_set(store, &iter, DBCOL_OBSINFO, obsinfo, -1);
1645 	g_free(obsinfo);
1646 
1647 	gtk_list_store_set(store, &iter, DBCOL_OFFSET, dw->sinfo[i].offset, -1);
1648     }
1649 
1650     dbwrapper_destroy(dw);
1651 }
1652 
add_rats_db_series_list(windata_t * vwin)1653 static int add_rats_db_series_list (windata_t *vwin)
1654 {
1655     FILE *fp;
1656     dbwrapper *dw;
1657 
1658     fp = gretl_fopen(vwin->fname, "rb");
1659     if (fp == NULL) {
1660 	file_read_errbox(vwin->fname);
1661 	return 1;
1662     }
1663 
1664     /* extract catalog from RATS file */
1665     dw = read_rats_db(vwin->fname, fp);
1666     fclose(fp);
1667 
1668     if (dw == NULL) {
1669 	gui_errmsg(1);
1670 	return 1;
1671     }
1672 
1673     insert_and_free_dbwrapper(dw, vwin->listbox);
1674     vwin->active_var = 0;
1675     db_drag_connect(vwin, GRETL_DBSERIES_PTR);
1676 
1677     return 0;
1678 }
1679 
add_pcgive_db_series_list(windata_t * vwin)1680 static int add_pcgive_db_series_list (windata_t *vwin)
1681 {
1682     gchar *in7name = NULL;
1683     FILE *fp = NULL;
1684     dbwrapper *dw;
1685     int err = 0;
1686 
1687     in7name = g_strdup_printf("%s.in7", vwin->fname);
1688     fp = gretl_fopen(in7name, "r");
1689     if (fp == NULL) {
1690 	err = 1;
1691 	file_read_errbox(in7name);
1692     }
1693 
1694     g_free(in7name);
1695     if (err) {
1696 	return err;
1697     }
1698 
1699     /* extract catalog from PcGive file */
1700     dw = read_pcgive_db(vwin->fname, fp);
1701     fclose(fp);
1702 
1703     if (dw == NULL) {
1704 	gui_errmsg(1);
1705 	return 1;
1706     }
1707 
1708     insert_and_free_dbwrapper(dw, vwin->listbox);
1709     vwin->active_var = 0;
1710     db_drag_connect(vwin, GRETL_DBSERIES_PTR);
1711 
1712     return 0;
1713 }
1714 
database_window(windata_t * vwin)1715 static GtkWidget *database_window (windata_t *vwin)
1716 {
1717     const char *titles[] = {
1718 	N_("Name"),
1719 	N_("Description"),
1720 	N_("Observations")
1721     };
1722     GType types[] = {
1723 	G_TYPE_STRING,
1724 	G_TYPE_STRING,
1725 	G_TYPE_STRING,
1726 	G_TYPE_INT
1727     };
1728     GtkWidget *box;
1729 
1730     /* FIXME column widths: we should ensure we show at
1731        least part of the observation-info column */
1732 
1733     box = gtk_vbox_new(FALSE, 0);
1734     vwin_add_list_box(vwin, GTK_BOX(box), 4, 1, types, titles, 0);
1735     g_signal_connect(G_OBJECT(vwin->listbox), "button-press-event",
1736 		     G_CALLBACK(popup_menu_handler),
1737 		     vwin->popup);
1738     gtk_widget_show(box);
1739 
1740     return box;
1741 }
1742 
1743 static void
add_series_to_list(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,int * list)1744 add_series_to_list (GtkTreeModel *model, GtkTreePath *path,
1745 		    GtkTreeIter *iter, int *list)
1746 {
1747     int row = tree_path_get_row_number(path);
1748 
1749     list[0] += 1;
1750     list[list[0]] = row;
1751 }
1752 
db_fill_selection_list(windata_t * vwin,int * list)1753 static void db_fill_selection_list (windata_t *vwin, int *list)
1754 {
1755     GtkTreeView *view = GTK_TREE_VIEW(vwin->listbox);
1756     GtkTreeSelection *sel;
1757 
1758     sel = gtk_tree_view_get_selection(view);
1759     gtk_tree_selection_selected_foreach(sel,
1760 					(GtkTreeSelectionForeachFunc)
1761 					add_series_to_list, list);
1762 }
1763 
db_get_selection_list(windata_t * vwin)1764 static int *db_get_selection_list (windata_t *vwin)
1765 {
1766     int n = vwin_selection_count(vwin, NULL);
1767     int *list = NULL;
1768 
1769     if (n == 0) {
1770 	return NULL;
1771     }
1772 
1773     list = gretl_list_new(n);
1774     if (list == NULL) {
1775 	nomem();
1776 	return NULL;
1777     }
1778 
1779     if (n == 1) {
1780 	list[1] = vwin->active_var;
1781     } else {
1782 	list[0] = 0;
1783 	db_fill_selection_list(vwin, list);
1784     }
1785 
1786     return list;
1787 }
1788 
db_role_to_dbtype(int role)1789 static int db_role_to_dbtype (int role)
1790 {
1791     if (role == PCGIVE_SERIES) {
1792 	return GRETL_PCGIVE_DB;
1793     } else if (role == REMOTE_SERIES) {
1794 	return GRETL_NATIVE_DB_WWW;
1795     } else if (role == RATS_SERIES) {
1796 	return GRETL_RATS_DB;
1797     } else {
1798 	return GRETL_NATIVE_DB;
1799     }
1800 }
1801 
get_db_series_info(windata_t * vwin,int action)1802 static dbwrapper *get_db_series_info (windata_t *vwin, int action)
1803 {
1804     GtkTreeView *view = GTK_TREE_VIEW(vwin->listbox);
1805     int *rowlist = NULL;
1806     int i, nsel, row = 0;
1807     char stobs[OBSLEN], endobs[OBSLEN];
1808     char pdc;
1809     dbwrapper *dw;
1810     int err = 0;
1811 
1812     /* get list of selected rows in database window */
1813     rowlist = db_get_selection_list(vwin);
1814     if (rowlist == NULL) {
1815 	return NULL;
1816     }
1817 
1818     /* count of selected rows */
1819     nsel = rowlist[0];
1820 
1821     /* construct wrapper with space for info on @nsel series */
1822     dw = dbwrapper_new(nsel, vwin->fname, db_role_to_dbtype(vwin->role));
1823     if (dw == NULL) {
1824 	free(rowlist);
1825 	return NULL;
1826     }
1827 
1828     dw->nv = nsel;
1829 
1830     /* loop across the selected rows, retrieve info on the
1831        associated db series and enter into the wrapper
1832     */
1833 
1834     for (i=0; i<rowlist[0]; i++) {
1835 	SERIESINFO *sinfo = &dw->sinfo[i];
1836 	gchar *tmp = NULL;
1837 
1838 	row = rowlist[i+1];
1839 	tree_view_get_int(view, row, DBCOL_OFFSET, &sinfo->offset);
1840 
1841 	*sinfo->varname = '\0';
1842 	tree_view_get_string(view, row, DBCOL_VARNAME, &tmp);
1843 	strncat(sinfo->varname, tmp, VNAMELEN - 1);
1844 	g_free(tmp);
1845 
1846 	tmp = NULL;
1847 	tree_view_get_string(view, row, DBCOL_DESCRIP, &tmp);
1848 	if (tmp != NULL) {
1849 	    series_info_set_description(sinfo, tmp);
1850 	    g_free(tmp);
1851 	}
1852 
1853 	tmp = NULL;
1854 	tree_view_get_string(view, row, DBCOL_OBSINFO, &tmp);
1855 	if (sscanf(tmp, "%c %10s %*s %10s %*s %*s %d",
1856 		   &pdc, stobs, endobs, &sinfo->nobs) != 4) {
1857 	    errbox(_("Failed to parse series information"));
1858 	    err = 1;
1859 	    goto bailout;
1860 	}
1861 	g_free(tmp);
1862 
1863 	sinfo->pd = 1;
1864 	sinfo->undated = 0;
1865 
1866 	if (pdc == 'M') {
1867 	    sinfo->pd = 12;
1868 	} else if (pdc == 'Q') {
1869 	    sinfo->pd = 4;
1870 	} else if (pdc == 'B') {
1871 	    sinfo->pd = 5;
1872 	} else if (pdc == 'S') {
1873 	    sinfo->pd = 6;
1874 	} else if (pdc == 'D') {
1875 	    sinfo->pd = 7;
1876 	} else if (pdc == 'W') {
1877 	    sinfo->pd = 52;
1878 	} else if (pdc == 'U') {
1879 	    sinfo->undated = 1;
1880 	}
1881 
1882 	if (i > 0 && sinfo->pd != dw->sinfo[0].pd) {
1883 	    /* this shouldn't happen */
1884 	    errbox("Can't operate on series with different frequencies");
1885 	    err = 1;
1886 	    goto bailout;
1887 	}
1888 
1889 	if (strchr(stobs, '/')) {
1890 	    /* daily data */
1891 	    char *q = stobs;
1892 	    char *p = strchr(stobs, '/');
1893 
1894 	    if (p - q == 4) {
1895 		strcpy(sinfo->stobs, q + 2);
1896 	    }
1897 	    q = endobs;
1898 	    p = strchr(endobs, '/');
1899 	    if (p && p - q == 4) {
1900 		strcpy(sinfo->endobs, q + 2);
1901 	    }
1902 	} else {
1903 	    sinfo->stobs[0] = 0;
1904 	    sinfo->endobs[0] = 0;
1905 	    strncat(sinfo->stobs, stobs, OBSLEN - 1);
1906 	    strncat(sinfo->endobs, endobs, OBSLEN - 1);
1907 	}
1908     }
1909 
1910  bailout:
1911 
1912     if (err) {
1913 	dbwrapper_destroy(dw);
1914 	dw = NULL;
1915     }
1916 
1917     free(rowlist);
1918 
1919     return dw;
1920 }
1921 
1922 /* the following two functions are used when a database has been
1923    specified on the gretl command line */
1924 
open_named_db_index(char * dbname)1925 gboolean open_named_db_index (char *dbname)
1926 {
1927     gboolean ret = FALSE;
1928     int action;
1929     FILE *fp;
1930 
1931     if (has_suffix(dbname, ".rat")) {
1932 	action = RATS_SERIES;
1933     } else if (has_suffix(dbname, ".bn7")) {
1934 	action = PCGIVE_SERIES;
1935     } else {
1936 	action = NATIVE_SERIES;
1937     }
1938 
1939     if (action == NATIVE_SERIES && !strcmp(dbname, "dbnomics")) {
1940 	warnbox("Sorry, this access to dbnomics not ready yet");
1941 	return ret;
1942     }
1943 
1944     fp = gretl_fopen(dbname, "rb");
1945 
1946     if (fp == NULL && action == NATIVE_SERIES &&
1947 	!has_suffix(dbname, ".bin")) {
1948 	strcat(dbname, ".bin");
1949 	fp = gretl_fopen(dbname, "rb");
1950     }
1951 
1952     if (fp == NULL) {
1953 	file_read_errbox(dbname);
1954     } else {
1955 	fclose(fp);
1956 	make_db_index_window(action, dbname, NULL, 0);
1957 	ret = TRUE;
1958     }
1959 
1960     return ret;
1961 }
1962 
open_named_remote_db_index(char * dbname)1963 gboolean open_named_remote_db_index (char *dbname)
1964 {
1965     gboolean ret = FALSE;
1966     char *getbuf = NULL;
1967     int err;
1968 
1969     err = retrieve_remote_db_index(dbname, &getbuf);
1970 
1971     if (err) {
1972 	show_network_error(NULL);
1973     } else if (getbuf != NULL && !strncmp(getbuf, "Couldn't open", 13)) {
1974 	errbox(getbuf);
1975     } else {
1976 	err = make_db_index_window(REMOTE_SERIES, dbname, getbuf, 0);
1977 	if (!err) {
1978 	    ret = TRUE;
1979 	}
1980     }
1981 
1982     free(getbuf);
1983 
1984     return ret;
1985 }
1986 
dbnomics_specific_series(GtkAction * action,gpointer data)1987 void dbnomics_specific_series (GtkAction *action, gpointer data)
1988 {
1989     char *datacode = NULL;
1990     int resp;
1991 
1992     if (data != NULL) {
1993 	windata_t *vwin = (windata_t *) data;
1994 
1995 	resp = dbnomics_dialog(&datacode, vwin->main);
1996     } else {
1997 	resp = dbnomics_dialog(&datacode, NULL);
1998     }
1999 
2000     if (!canceled(resp)) {
2001 	dbnomics_get_series_call(datacode);
2002     }
2003 
2004     free(datacode);
2005 }
2006 
open_dbnomics_series(GtkWidget * w,gpointer data)2007 void open_dbnomics_series (GtkWidget *w, gpointer data)
2008 {
2009     windata_t *vwin = (windata_t *) data;
2010     gchar *scode = NULL, *path = NULL;
2011     gchar *datacode;
2012 
2013     path = g_object_get_data(G_OBJECT(vwin->listbox), "path");
2014     tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2015 			 vwin->active_var, COL_DBNAME, &scode);
2016 
2017     datacode = g_strdup_printf("%s/%s", path, scode);
2018     dbnomics_get_series_call(datacode);
2019     g_free(datacode);
2020 }
2021 
dbn_general_search_results(const gchar * key,gretl_array * a)2022 static int dbn_general_search_results (const gchar *key,
2023 				       gretl_array *a)
2024 {
2025     int n = gretl_array_get_length(a);
2026     PRN *prn = NULL;
2027     int err, n_ok = 0;
2028 
2029     if (n == 0) {
2030 	return 0;
2031     }
2032 
2033     err = bufopen(&prn);
2034 
2035     if (!err) {
2036 	const char *pcode, *dcode, *name;
2037 	gretl_bundle *b;
2038 	int i;
2039 
2040 	pprintf(prn, _("Results of DB.NOMICS search on '%s'\n"), key);
2041 	pputs(prn, "Provider/Dataset : description\n\n");
2042 
2043 	for (i=0; i<n; i++) {
2044 	    b = gretl_array_get_bundle(a, i);
2045 	    pcode = gretl_bundle_get_string(b, "provider_code", NULL);
2046 	    dcode = gretl_bundle_get_string(b, "code", NULL);
2047 	    name = gretl_bundle_get_string(b, "name", NULL);
2048 	    if (pcode != NULL && dcode != NULL && name != NULL) {
2049 		pprintf(prn, "%d <@dbn=\"%s/%s\"> : %s\n\n", i+1,
2050 			pcode, dcode, name);
2051 		n_ok++;
2052 	    }
2053 	}
2054 	if (n_ok > 0) {
2055 	    const char *title = "gretl: DB.NOMICS search";
2056 
2057 	    view_buffer(prn, 78, 350, title, VIEW_DBSEARCH, NULL);
2058 	} else {
2059 	    gretl_print_destroy(prn);
2060 	}
2061     }
2062 
2063     return n_ok;
2064 }
2065 
dbn_dataset_search_results(const char * key,const char * prov,const char * dset,int offset,gretl_array * a,windata_t * prev_vwin)2066 static int dbn_dataset_search_results (const char *key,
2067 				       const char *prov,
2068 				       const char *dset,
2069 				       int offset,
2070 				       gretl_array *a,
2071 				       windata_t *prev_vwin)
2072 {
2073     int n = gretl_array_get_length(a);
2074     PRN *prn = NULL;
2075     int err, n_ok = 0;
2076 
2077     if (n == 0) {
2078 	return 0;
2079     }
2080 
2081     err = bufopen(&prn);
2082 
2083     if (!err) {
2084 	const char *scode, *name;
2085 	gretl_bundle *b;
2086 	int more = 0;
2087 	int i, ntot;
2088 
2089 	b = gretl_array_get_bundle(a, 0);
2090 	ntot = gretl_bundle_get_int(b, "ntot", NULL);
2091 
2092 	pprintf(prn, _("DB.NOMICS search on '%s' in dataset %s/%s\n"),
2093 		key, prov, dset);
2094 	pprintf(prn, "Matching series %d to %d of %d", offset + 1,
2095 		offset + n, ntot);
2096 
2097 	if (ntot > offset + n) {
2098 	    pputs(prn, " [ <@dbn=\"_NEXT_\"> ]\n\n");
2099 	    more = 1;
2100 	} else {
2101 	    pputs(prn, "\n\n");
2102 	}
2103 
2104 	for (i=0; i<n; i++) {
2105 	    b = gretl_array_get_bundle(a, i);
2106 	    scode = gretl_bundle_get_string(b, "code", NULL);
2107 	    name = gretl_bundle_get_string(b, "name", NULL);
2108 	    if (scode != NULL && name != NULL) {
2109 		pprintf(prn, "%d <@dbn=\"%s;%s/%s/%s\"> : %s\n\n", i+1,
2110 			scode, prov, dset, scode, name);
2111 		n_ok++;
2112 	    }
2113 	}
2114 
2115 	if (prev_vwin != NULL) {
2116 	    /* we should replace the content of @prev_vwin */
2117 	    char *buf = gretl_print_steal_buffer(prn);
2118 
2119 	    /* update the offset record on prev_vwin->text */
2120 	    widget_set_int(prev_vwin->text, "offset", offset);
2121 	    /* clear and replace with new results */
2122 	    textview_clear_text(prev_vwin->text);
2123 	    textview_set_text_dbsearch(prev_vwin, buf);
2124 	    gretl_print_destroy(prn);
2125 	    return 1;
2126 	} else if (n_ok > 0) {
2127 	    /* we'll open a new window */
2128 	    const char *title = "gretl: DB.NOMICS search";
2129 	    windata_t *vwin;
2130 
2131 	    vwin = view_buffer(prn, 78, 350, title, VIEW_DBSEARCH, NULL);
2132 	    if (vwin != NULL && more) {
2133 		widget_set_int(vwin->text, "offset", offset);
2134 		g_object_set_data_full(G_OBJECT(vwin->text), "key",
2135 				       g_strdup(key), g_free);
2136 		g_object_set_data_full(G_OBJECT(vwin->text), "prov",
2137 				       g_strdup(prov), g_free);
2138 		g_object_set_data_full(G_OBJECT(vwin->text), "dset",
2139 				       g_strdup(dset), g_free);
2140 	    }
2141 	} else {
2142 	    gretl_print_destroy(prn);
2143 	}
2144     }
2145 
2146     return n_ok;
2147 }
2148 
2149 #define SEARCH_CHUNK 80
2150 
2151 static gchar *dbnomics_search_string;
2152 
maybe_fill_dbn_finder(GtkWidget * entry)2153 void maybe_fill_dbn_finder (GtkWidget *entry)
2154 {
2155     if (dbnomics_search_string != NULL) {
2156 	gtk_entry_set_text(GTK_ENTRY(entry), dbnomics_search_string);
2157     }
2158 }
2159 
2160 /* The @key string is passed here when "all DB.NOMICS"
2161    is selected as the search space in the dbnomics
2162    providers window, or when "this database" is selected
2163    in a dbnomics dataset window.
2164 */
2165 
dbnomics_search(gchar * key,windata_t * vwin)2166 void dbnomics_search (gchar *key, windata_t *vwin)
2167 {
2168     gretl_array *a = NULL;
2169     int n_found = 0;
2170     int err = 0;
2171 
2172     if (key != NULL) {
2173 	if (dbnomics_search_string == NULL) {
2174 	    dbnomics_search_string = g_strdup(key);
2175 	} else if (strcmp(dbnomics_search_string, key)) {
2176 	    g_free(dbnomics_search_string);
2177 	    dbnomics_search_string = g_strdup(key);
2178 	}
2179     }
2180 
2181     if (vwin->role == VIEW_DBSEARCH) {
2182 	/* we're called in "next results" mode */
2183 	const gchar *key, *prov, *dset;
2184 	int offset;
2185 
2186 	key = g_object_get_data(G_OBJECT(vwin->text), "key");
2187 	prov = g_object_get_data(G_OBJECT(vwin->text), "prov");
2188 	dset = g_object_get_data(G_OBJECT(vwin->text), "dset");
2189 	offset = widget_get_int(vwin->text, "offset");
2190 
2191 	offset += SEARCH_CHUNK;
2192 	a = dbnomics_search_call(key, prov, dset, SEARCH_CHUNK, offset, &err);
2193 	if (!err) {
2194 	    n_found = dbn_dataset_search_results(key, prov, dset, offset, a, vwin);
2195 	}
2196 	key = NULL; /* don't free it! */
2197     } else if (vwin->role == DBNOMICS_DB) {
2198 	/* searching "selected dataset" in datasets window */
2199 	const gchar *prov = g_object_get_data(G_OBJECT(vwin->listbox),
2200 					       "provider");
2201 	gchar *dset = NULL;
2202 
2203 	tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2204 			     vwin->active_var, COL_DBNAME, &dset);
2205 	a = dbnomics_search_call(key, prov, dset, SEARCH_CHUNK, 0, &err);
2206 	if (!err) {
2207 	    n_found = dbn_dataset_search_results(key, prov, dset, 0, a, NULL);
2208 	}
2209 	g_free(dset);
2210     } else if (vwin->role == DBNOMICS_SERIES) {
2211 	/* searching from a particular dataset window */
2212 	const gchar *path = g_object_get_data(G_OBJECT(vwin->listbox),
2213 					      "path");
2214 	const gchar *p = strchr(path, '/');
2215 	const gchar *dset = p + 1;
2216 	gchar *prov = g_strndup(path, p - path);
2217 
2218 	a = dbnomics_search_call(key, prov, dset, SEARCH_CHUNK, 0, &err);
2219 	if (!err) {
2220 	    n_found = dbn_dataset_search_results(key, prov, dset, 0, a, NULL);
2221 	}
2222 	g_free(prov);
2223     } else {
2224 	/* top-level search */
2225 	a = dbnomics_search_call(key, NULL, NULL, SEARCH_CHUNK, 0, &err);
2226 	if (!err) {
2227 	    n_found = dbn_general_search_results(key, a);
2228 	}
2229     }
2230 
2231     if (!err && n_found == 0) {
2232 	warnbox(_("No matches were found"));
2233     }
2234 
2235     gretl_array_destroy(a);
2236 
2237     /* only if this arg is a GTK-allocated string */
2238     if (key != NULL) {
2239 	g_free(key);
2240     }
2241 }
2242 
open_db_index(GtkWidget * w,gpointer data)2243 void open_db_index (GtkWidget *w, gpointer data)
2244 {
2245     windata_t *vwin = (windata_t *) data;
2246     gchar *fname = NULL, *dbdir = NULL;
2247     char dbfile[MAXLEN];
2248     int action = NATIVE_SERIES;
2249     int idx = 0;
2250 
2251     tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2252 			 vwin->active_var, COL_DBNAME, &fname);
2253 
2254     if (has_suffix(fname, ".rat")) {
2255 	action = RATS_SERIES;
2256     }
2257 
2258     tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2259 			 vwin->active_var, (action == RATS_SERIES)? 1 : 2,
2260 			 &dbdir);
2261 
2262     gretl_build_path(dbfile, dbdir, fname, NULL);
2263     g_free(fname);
2264     g_free(dbdir);
2265 
2266     if (action == NATIVE_SERIES) {
2267 	GtkTreeModel *mod;
2268 
2269 	mod = gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox));
2270 	idx = tree_model_count_rows(mod) > 1;
2271     }
2272 
2273     make_db_index_window(action, dbfile, NULL, idx);
2274 
2275     if (action == NATIVE_SERIES) {
2276 	/* close the window from which this db was selected */
2277 	gtk_widget_destroy(vwin->main);
2278     }
2279 }
2280 
open_remote_db_index(GtkWidget * w,gpointer data)2281 void open_remote_db_index (GtkWidget *w, gpointer data)
2282 {
2283     GtkTreeSelection *sel;
2284     GtkTreeIter iter;
2285     GtkTreeModel *model;
2286     char *getbuf = NULL;
2287     gchar *fname = NULL;
2288     windata_t *vwin = (windata_t *) data;
2289     int err;
2290 
2291     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(vwin->listbox));
2292     if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
2293 	return;
2294     }
2295 
2296     gtk_tree_model_get(model, &iter, 0, &fname, -1);
2297     if (fname == NULL || *fname == '\0') {
2298 	g_free(fname);
2299 	return;
2300     }
2301 
2302     update_statusline(vwin, _("Retrieving data..."));
2303     err = retrieve_remote_db_index(fname, &getbuf);
2304 
2305     if (err) {
2306 	show_network_error(vwin);
2307     } else {
2308 	update_statusline(vwin, "OK");
2309 	make_db_index_window(REMOTE_SERIES, fname, getbuf, 0);
2310     }
2311 
2312     g_free(fname);
2313     free(getbuf);
2314 }
2315 
open_dbnomics_provider(GtkWidget * w,gpointer data)2316 void open_dbnomics_provider (GtkWidget *w, gpointer data)
2317 {
2318     windata_t *vwin = (windata_t *) data;
2319     GtkTreeIter iter;
2320     GtkTreeModel *model;
2321     GtkTreeSelection *sel;
2322     gchar *pname = NULL;
2323 
2324     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(vwin->listbox));
2325     if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
2326 	return;
2327     }
2328 
2329     gtk_tree_model_get(model, &iter, 0, &pname, -1);
2330     if (pname != NULL && *pname != '\0') {
2331 	display_files(DBNOMICS_DB, pname);
2332     }
2333     g_free(pname);
2334 }
2335 
get_db_provider_and_name(windata_t * vwin,const gchar ** provider,gchar ** dsname)2336 static int get_db_provider_and_name (windata_t *vwin,
2337 				     const gchar **provider,
2338 				     gchar **dsname)
2339 {
2340     GtkTreeSelection *sel;
2341     GtkTreeIter iter;
2342     GtkTreeModel *model;
2343 
2344     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(vwin->listbox));
2345     if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
2346 	return E_DATA;
2347     }
2348     gtk_tree_model_get(model, &iter, 0, dsname, -1);
2349     if (*dsname == NULL || **dsname == '\0') {
2350 	g_free(dsname);
2351 	return E_DATA;
2352     }
2353     *provider = g_object_get_data(G_OBJECT(vwin->listbox), "provider");
2354     if (*provider == NULL) {
2355 	g_free(*dsname);
2356 	return E_DATA;
2357     }
2358 
2359     return 0;
2360 }
2361 
2362 /* "open" a dbnomics dataset in the sense of showing the series
2363    it contains (or a portion thereof if there are many series)
2364 */
2365 
open_dbnomics_dataset(GtkWidget * w,gpointer data)2366 void open_dbnomics_dataset (GtkWidget *w, gpointer data)
2367 {
2368     windata_t *vwin = (windata_t *) data;
2369     const gchar *provider = NULL;
2370     gchar *dsname = NULL;
2371     int err;
2372 
2373     err = get_db_provider_and_name(vwin, &provider, &dsname);
2374 
2375     if (!err) {
2376 	gchar *arg = g_strdup_printf("%s/%s", provider, dsname);
2377 
2378 	g_free(dsname);
2379 	display_files(DBNOMICS_SERIES, arg);
2380 	g_free(arg);
2381     }
2382 }
2383 
2384 /* "open" a dbnomics dataset in the sense of showing its
2385    "dimensions": topics/subjects/indicators and countries,
2386    if applicable.
2387 */
2388 
show_dbnomics_dimensions(GtkWidget * w,gpointer data)2389 void show_dbnomics_dimensions (GtkWidget *w, gpointer data)
2390 {
2391     windata_t *vwin = (windata_t *) data;
2392     const gchar *provider = NULL;
2393     gchar *dsname = NULL;
2394     int err;
2395 
2396     err = get_db_provider_and_name(vwin, &provider, &dsname);
2397 
2398     if (!err) {
2399 	err = dbnomics_get_dimensions_call(provider, dsname);
2400 	g_free(dsname);
2401     }
2402 }
2403 
2404 #define INFOLEN 100
2405 
parse_db_header(const char * buf,unsigned * idxlen,unsigned * datalen,unsigned * cblen,int * pdfdoc)2406 static int parse_db_header (const char *buf, unsigned *idxlen,
2407 			    unsigned *datalen, unsigned *cblen,
2408 			    int *pdfdoc)
2409 {
2410     char *p;
2411     int err = 0;
2412 
2413     *cblen = 0;
2414 
2415     /* length of index file (required) */
2416     if (sscanf(buf, "%u", idxlen) != 1) {
2417 	err = 1;
2418     }
2419 
2420     /* length of data (required under "new" system) */
2421     if (!err) {
2422 	p = strchr(buf, '\n');
2423 	if (p == NULL) {
2424 	    err = 1;
2425 	} else if (sscanf(p + 1, "%u", datalen) != 1) {
2426 	    err = 1;
2427 	}
2428     }
2429 
2430     /* length of codebook (optional) */
2431     if (!err) {
2432 	p = strchr(p + 1, '\n');
2433 	if (p != NULL) {
2434 	    int cbl;
2435 
2436 	    if (sscanf(p + 1, "%u", &cbl) == 1) {
2437 		*cblen = cbl;
2438 		if (strstr(p, ".pdf")) {
2439 		    *pdfdoc = 1;
2440 		}
2441 	    }
2442 	}
2443     }
2444 
2445     return err;
2446 }
2447 
ggz_extract(char * ggzname)2448 static int ggz_extract (char *ggzname)
2449 {
2450     gzFile fgz = NULL;
2451     FILE *fidx = NULL, *fbin = NULL, *fcbk = NULL;
2452     unsigned idxlen, datalen, cblen = 0;
2453     int bgot, bytesleft, pdfdoc = 0;
2454     char idxname[MAXLEN], binname[MAXLEN], cbname[MAXLEN];
2455     char gzbuf[GRETL_BUFSIZE];
2456 #if G_BYTE_ORDER == G_BIG_ENDIAN
2457     netfloat nf;
2458     float val;
2459 #endif
2460     int err = 0;
2461 
2462     switch_ext(idxname, ggzname, "idx");
2463     switch_ext(binname, ggzname, "bin");
2464     cbname[0] = '\0';
2465 
2466     fgz = gzopen(ggzname, "rb");
2467     if (fgz == NULL) {
2468 	file_read_errbox(ggzname);
2469         return E_FOPEN;
2470     }
2471 
2472     fidx = gretl_fopen(idxname, "wb");
2473     if (fidx == NULL) {
2474 	file_write_errbox(idxname);
2475 	err = E_FOPEN;
2476 	goto bailout;
2477     }
2478 
2479     fbin = gretl_fopen(binname, "wb");
2480     if (fbin == NULL) {
2481 	file_write_errbox(binname);
2482 	err = E_FOPEN;
2483 	goto bailout;
2484     }
2485 
2486     memset(gzbuf, 0, GRETL_BUFSIZE);
2487     gzread(fgz, gzbuf, INFOLEN);
2488 
2489     if (parse_db_header(gzbuf, &idxlen, &datalen, &cblen, &pdfdoc)) {
2490 	fputs("Error reading info buffer: failed to get byte counts\n",
2491 	      stderr);
2492 	fprintf(stderr, "bad infobuf:\n%s\n", gzbuf);
2493 	err = 1;
2494 	goto bailout;
2495     }
2496 
2497     if (cblen > 0) {
2498 	switch_ext(cbname, ggzname, pdfdoc ? "pdf" : "cb");
2499 	fcbk = gretl_fopen(cbname, "wb");
2500 	if (fcbk == NULL) {
2501 	    cblen = pdfdoc = 0;
2502 	}
2503     }
2504 
2505     bytesleft = idxlen;
2506     while (bytesleft > 0) {
2507 	memset(gzbuf, 0, GRETL_BUFSIZE);
2508 	bgot = gzread(fgz, gzbuf, (bytesleft > GRETL_BUFSIZE)?
2509 		      GRETL_BUFSIZE : bytesleft);
2510 	if (bgot <= 0) break;
2511 	bytesleft -= bgot;
2512 	fwrite(gzbuf, 1, bgot, fidx);
2513     }
2514 
2515     if (bytesleft > 0) {
2516 	fputs("Error reading database info buffer\n", stderr);
2517 	err = 1;
2518 	goto bailout;
2519     }
2520 
2521     bytesleft = datalen;
2522 
2523     while (bytesleft > 0) {
2524 #if G_BYTE_ORDER == G_BIG_ENDIAN
2525         if ((bgot = gzread(fgz, gzbuf, sizeof(long) + sizeof(short))) > 0) {
2526 	    /* read "netfloats" and write floats */
2527 	    memcpy(&(nf.frac), gzbuf, sizeof(long));
2528 	    memcpy(&(nf.exp), gzbuf + sizeof(long), sizeof(short));
2529 	    val = retrieve_float(nf);
2530 	    fwrite(&val, sizeof(float), 1, fbin);
2531 	    bytesleft -= sizeof(dbnumber);
2532 	} else break;
2533 #else
2534 	memset(gzbuf, 0, GRETL_BUFSIZE);
2535 	bgot = gzread(fgz, gzbuf, (bytesleft > GRETL_BUFSIZE)?
2536 		      GRETL_BUFSIZE : bytesleft);
2537 	if (bgot <= 0) break;
2538 	bytesleft -= bgot;
2539 	fwrite(gzbuf, 1, bgot, fbin);
2540 #endif
2541     }
2542 
2543     if (bytesleft > 0) {
2544 	fputs("Error reading database data\n", stderr);
2545 	err = 1;
2546 	goto bailout;
2547     }
2548 
2549     bytesleft = cblen;
2550 
2551     while (bytesleft > 0) {
2552 	memset(gzbuf, 0, GRETL_BUFSIZE);
2553 	bgot = gzread(fgz, gzbuf, (bytesleft > GRETL_BUFSIZE)?
2554 		      GRETL_BUFSIZE : bytesleft);
2555 	if (bgot <= 0) break;
2556 	bytesleft -= bgot;
2557 	fwrite(gzbuf, 1, bgot, fcbk);
2558     }
2559 
2560     if (bytesleft > 0) {
2561 	fputs("Error reading database codebook\n", stderr);
2562 	err = 1;
2563     }
2564 
2565  bailout:
2566 
2567     if (fgz != NULL) gzclose(fgz);
2568     if (fidx != NULL) fclose(fidx);
2569     if (fbin != NULL) fclose(fbin);
2570     if (fcbk != NULL) fclose(fcbk);
2571 
2572     if (err) {
2573 	/* clean up botched files */
2574 	gretl_remove(idxname);
2575 	gretl_remove(binname);
2576 	if (cbname[0] != '\0') {
2577 	    gretl_remove(cbname);
2578 	}
2579     }
2580 
2581     gretl_remove(ggzname);
2582 
2583     return err;
2584 }
2585 
offer_db_open(char * target,windata_t * vwin)2586 static void offer_db_open (char *target, windata_t *vwin)
2587 {
2588     int resp = yes_no_dialog("gretl",
2589 			     _("Database installed.\n"
2590 			       "Open it now?"),
2591 			     vwin_toplevel(vwin));
2592 
2593     if (resp == GRETL_YES) {
2594 	char dbpath[MAXLEN];
2595 
2596 	strcpy(dbpath, target);
2597 	strcpy(strrchr(dbpath, '.'), ".bin");
2598 	open_named_db_index(dbpath);
2599     }
2600 }
2601 
get_target_in_home(char * targ,int code,const char * objname,const char * ext)2602 static int get_target_in_home (char *targ, int code,
2603 			       const char *objname,
2604 			       const char *ext)
2605 {
2606     GString *gs = g_string_new(NULL);
2607 #ifdef OS_OSX
2608     const char *savedir = gretl_app_support_dir();
2609 #else
2610     const char *savedir = gretl_dotdir();
2611 #endif
2612     int err = 0;
2613 
2614     if (savedir == NULL || *savedir == '\0') {
2615 	err = E_FOPEN;
2616     } else {
2617 	int subdir = 1;
2618 
2619 	if (code == REMOTE_FUNC_FILES) {
2620 	    g_string_append_printf(gs, "%sfunctions", savedir);
2621 	} else if (code == REMOTE_DB) {
2622 	    g_string_append_printf(gs, "%sdb", savedir);
2623 	} else if (code == REMOTE_DATA_PKGS) {
2624 	    g_string_append_printf(gs, "%sdata", savedir);
2625 	} else {
2626 	    g_string_append_printf(gs, "%s%s%s", savedir, objname, ext);
2627 	    subdir = 0;
2628 	}
2629 
2630 	if (subdir) {
2631 	    err = gretl_mkdir(gs->str);
2632 	    if (!err) {
2633 		g_string_append_c(gs, SLASH);
2634 		g_string_append(gs, objname);
2635 		g_string_append(gs, ext);
2636 	    }
2637 	}
2638     }
2639 
2640     strcpy(targ, gs->str);
2641     g_string_free(gs, TRUE);
2642 
2643     return err;
2644 }
2645 
2646 #if !defined(G_OS_WIN32) && !defined(OS_OSX)
2647 
get_system_target(char * targ,int code,const char * objname,const char * ext)2648 static void get_system_target (char *targ, int code,
2649 			       const char *objname,
2650 			       const char *ext)
2651 {
2652     if (code == REMOTE_DB) {
2653 	get_default_dir_for_action(targ, SAVE_REMOTE_DB);
2654     } else if (code == REMOTE_DATA_PKGS) {
2655 	get_default_dir_for_action(targ, SAVE_DATA_PKG);
2656     } else if (code == REMOTE_FUNC_FILES) {
2657 	get_default_dir_for_action(targ, SAVE_FUNCTIONS);
2658     }
2659 
2660     strcat(targ, objname);
2661     strcat(targ, ext);
2662 }
2663 
2664 #endif
2665 
2666 enum {
2667     REAL_INSTALL,
2668     TMP_INSTALL
2669 };
2670 
2671 /* Try to find a suitable path, for which the user has write
2672    permission, for installing a database or collection of
2673    data files.
2674 */
2675 
get_writable_target(int code,char * objname)2676 static char *get_writable_target (int code, char *objname)
2677 {
2678     const char *ext;
2679     char *targ;
2680     int done_home = 0;
2681     int err = 0;
2682 
2683 #if 0
2684     fprintf(stderr, "get_writable_target, starting\n");
2685 #endif
2686 
2687     targ = mymalloc(MAXLEN);
2688     if (targ == NULL) {
2689 	return NULL;
2690     }
2691 
2692     *targ = '\0';
2693 
2694     if (code == REMOTE_DB) {
2695 	ext = ".ggz";
2696     } else {
2697 	ext = ".tar.gz";
2698     }
2699 
2700 #if defined(G_OS_WIN32) || defined(OS_OSX)
2701     /* On macOS we prefer writing to ~/Library/Application Support
2702        rather than /Applications/Gretl.app, and on Windows let's
2703        steer clear of Program Files.
2704     */
2705     err = get_target_in_home(targ, code, objname, ext);
2706     done_home = 1;
2707 #else
2708     get_system_target(targ, code, objname, ext);
2709 #endif
2710 
2711     if (!err) {
2712 	err = gretl_test_fopen(targ, "w");
2713 	if (err == EACCES && !done_home) {
2714 	    /* permissions problem: write to home dir instead */
2715 	    err = get_target_in_home(targ, code, objname, ext);
2716 	}
2717     }
2718 
2719     if (err) {
2720 	file_write_errbox(targ);
2721 	free(targ);
2722 	targ = NULL;
2723     }
2724 
2725 #if 0
2726     fprintf(stderr, "writable targ: '%s'\n", targ);
2727 #endif
2728 
2729     return targ;
2730 }
2731 
unpack_book_data(const char * fname)2732 static int unpack_book_data (const char *fname)
2733 {
2734     char *p, *path = g_strdup(fname);
2735     int err = 0;
2736 
2737     p = strrslash(path);
2738     if (p != NULL) {
2739 	*p = '\0';
2740     }
2741 
2742     if (gretl_chdir(path) != 0) {
2743 	err = E_FOPEN;
2744     }
2745 
2746     if (!err) {
2747 	err = gretl_untar(fname);
2748     }
2749 
2750     g_free(path);
2751 
2752     return err;
2753 }
2754 
make_gfn_path(const char * pkgname,const char * fpath)2755 static gchar *make_gfn_path (const char *pkgname,
2756 			     const char *fpath)
2757 {
2758     if (fpath == NULL) {
2759 	fpath = gretl_function_package_path();
2760     }
2761     return g_strdup_printf("%s%s%c%s.gfn", fpath,
2762 			   pkgname, SLASH, pkgname);
2763 }
2764 
2765 #define STATUS_COLUMN  5
2766 #define ZIPFILE_COLUMN 6
2767 #define DEPENDS_COLUMN 7
2768 
try_install_dependency(const char * pkgname,const char * instpath)2769 static int try_install_dependency (const char *pkgname,
2770 				   const char *instpath)
2771 {
2772     char *fname = NULL;
2773     int filetype = 0;
2774     int err = 0;
2775 
2776     /* let the server tell us the correct suffix */
2777     fname = retrieve_remote_pkg_filename(pkgname, &err);
2778     if (!err) {
2779 	filetype = strstr(fname, ".zip") ? 2 : 1;
2780      }
2781 
2782     if (filetype) {
2783         gchar *fullname = g_strdup_printf("%s%s", instpath, fname);
2784 
2785 	/* get file from gretl server */
2786 	err = retrieve_remote_function_package(fname, fullname);
2787         if (!err && filetype == 2) {
2788             err = gretl_unzip_into(fullname, instpath);
2789             if (!err) {
2790                 /* delete the zipfile */
2791                 gretl_remove(fullname);
2792             }
2793         }
2794         g_free(fullname);
2795     }
2796 
2797     free(fname);
2798 
2799     return err;
2800 }
2801 
gfn_install_notify(const gchar * objname,const gchar * gfnpath,windata_t * vwin)2802 static void gfn_install_notify (const gchar *objname,
2803 				const gchar *gfnpath,
2804 				windata_t *vwin)
2805 {
2806     windata_t *local = get_local_viewer(vwin->role);
2807 
2808     if (!gui_function_pkg_query_register(gfnpath, vwin->main)) {
2809 	infobox_printf(_("Installed %s"), objname);
2810     }
2811     list_store_set_string(GTK_TREE_VIEW(vwin->listbox),
2812 			  vwin->active_var, STATUS_COLUMN,
2813 			  _("Up to date"));
2814     if (local != NULL) {
2815 	populate_filelist(local, NULL);
2816     }
2817 }
2818 
gui_install_gfn(const gchar * objname,int zipfile,gchar * depends,windata_t * vwin)2819 static int gui_install_gfn (const gchar *objname,
2820 			    int zipfile,
2821 			    gchar *depends,
2822 			    windata_t *vwin)
2823 {
2824     const char *instpath = gretl_function_package_path();
2825     int err = 0;
2826 
2827     if (depends != NULL) {
2828 	/* try to handle dependencies first */
2829 	char *pkgpath, **Deps;
2830 	int i, n_deps;
2831 
2832 	Deps = gretl_string_split(depends, &n_deps, NULL);
2833 	for (i=0; i<n_deps && !err; i++) {
2834 	    pkgpath = gretl_function_package_get_path(Deps[i], PKG_ALL);
2835 	    if (pkgpath == NULL) {
2836 		fprintf(stderr, "dependency %s not satisfied: try download\n", Deps[i]);
2837 		err = try_install_dependency(Deps[i], instpath);
2838 		free(pkgpath);
2839 	    } else {
2840 		free(pkgpath);
2841 	    }
2842 	}
2843 	strings_array_free(Deps, n_deps);
2844     }
2845 
2846     if (!err) {
2847 	const char *ext = zipfile ? ".zip" : ".gfn";
2848 	gchar *basename = g_strdup_printf("%s%s", objname, ext);
2849 	gchar *fullname;
2850 
2851 	fullname = g_strdup_printf("%s%s", instpath, basename);
2852 	err = retrieve_remote_function_package(basename, fullname);
2853 	if (!err && zipfile) {
2854 	    err = gretl_unzip_into(fullname, instpath);
2855 	    gretl_remove(fullname);
2856 	    if (!err) {
2857 		g_free(fullname);
2858 		fullname = g_strdup_printf("%s%s%c%s.gfn", instpath,
2859 					   objname, SLASH, objname);
2860 	    }
2861 	}
2862 	if (!err) {
2863 	    gfn_install_notify(objname, fullname, vwin);
2864 	}
2865 	g_free(fullname);
2866 	g_free(basename);
2867     }
2868 
2869     return err;
2870 }
2871 
2872 /* note: @vwin here is the source viewer window displaying the
2873    remote file (database, or datafiles package, or function package)
2874    that is to be installed onto the local machine.
2875 */
2876 
install_file_from_server(GtkWidget * w,windata_t * vwin)2877 void install_file_from_server (GtkWidget *w, windata_t *vwin)
2878 {
2879     gchar *objname = NULL;
2880     gchar *depends = NULL;
2881     gchar *tarname = NULL;
2882     char *targ = NULL;
2883     gboolean zipfile = FALSE;
2884     int err = 0;
2885 
2886     /* note: addon files are handled separately, by the function
2887        install_addon_callback() in datafiles.c
2888     */
2889 
2890     if (vwin->role == REMOTE_DB) {
2891 	/* database files */
2892 	GtkTreeSelection *sel;
2893 	GtkTreeModel *model;
2894 	GtkTreeIter iter;
2895 
2896 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(vwin->listbox));
2897 	if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
2898 	    gtk_tree_model_get(model, &iter, 0, &objname, -1);
2899 	}
2900     } else {
2901 	/* datafiles or function package */
2902 	tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2903 			     vwin->active_var, 0, &objname);
2904 	if (vwin->role == REMOTE_FUNC_FILES) {
2905 	    tree_view_get_bool(GTK_TREE_VIEW(vwin->listbox),
2906 			       vwin->active_var, ZIPFILE_COLUMN, &zipfile);
2907 	    /* FIXME is this kosher? */
2908 	    tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
2909 				 vwin->active_var, DEPENDS_COLUMN, &depends);
2910 	}
2911     }
2912 
2913     if (objname == NULL || *objname == '\0') {
2914 	g_free(objname);
2915 	return;
2916     }
2917 
2918     if (!zipfile && vwin->role != REMOTE_FUNC_FILES) {
2919 	targ = get_writable_target(vwin->role, objname);
2920 	if (targ == NULL) {
2921 	    g_free(objname);
2922 	    return;
2923 	}
2924     }
2925 
2926     if (vwin->role == REMOTE_FUNC_FILES) {
2927 	err = gui_install_gfn(objname, zipfile, depends, vwin);
2928     } else if (vwin->role == REMOTE_DATA_PKGS) {
2929 	tarname = g_strdup_printf("%s.tar.gz", objname);
2930 	err = retrieve_remote_datafiles_package(tarname, targ);
2931     } else if (vwin->role == REMOTE_DB) {
2932 #if G_BYTE_ORDER == G_BIG_ENDIAN
2933 	err = retrieve_remote_db(objname, targ, GRAB_NBO_DATA);
2934 #else
2935 	err = retrieve_remote_db(objname, targ, GRAB_DATA);
2936 #endif
2937     }
2938 
2939     if (err) {
2940 	show_network_error(NULL);
2941     } else if (vwin->role == REMOTE_DATA_PKGS) {
2942 	fprintf(stderr, "downloaded '%s'\n", targ);
2943 	err = unpack_book_data(targ);
2944 	gretl_remove(targ);
2945 	if (err) {
2946 	    errbox(_("Error unzipping compressed data"));
2947 	} else {
2948 	    infobox("Restart gretl to access this database");
2949 	}
2950     } else if (vwin->role == REMOTE_DB) {
2951 	/* gretl-zipped database package */
2952 	fprintf(stderr, "downloaded '%s'\n", targ);
2953 	err = ggz_extract(targ);
2954 	if (err) {
2955 	    if (err != E_FOPEN) {
2956 		errbox(_("Error unzipping compressed data"));
2957 	    }
2958 	} else {
2959 	    windata_t *local = get_local_viewer(vwin->role);
2960 
2961 	    tree_store_set_string(GTK_TREE_VIEW(vwin->listbox),
2962 				  vwin->active_var, 2,
2963 				  _("Up to date"));
2964 	    if (local != NULL) {
2965 		populate_filelist(local, NULL);
2966 	    } else if (targ != NULL) {
2967 		offer_db_open(targ, vwin);
2968 	    }
2969 	}
2970     }
2971 
2972     g_free(objname);
2973     g_free(depends);
2974     g_free(tarname);
2975     free(targ);
2976 }
2977 
2978 /* called from within datafiles.c, when dragging a
2979    remote database or function package from its
2980    "on server" window to the associated local
2981    window */
2982 
drag_file_from_server(guint info)2983 void drag_file_from_server (guint info)
2984 {
2985     windata_t *vwin = NULL;
2986 
2987     if (info == GRETL_REMOTE_DB_PTR ||
2988 	info == GRETL_REMOTE_FNPKG_PTR) {
2989 	vwin = vwin_drag_src;
2990 	vwin_drag_src = NULL;
2991     }
2992 
2993     if (vwin != NULL) {
2994 	install_file_from_server(NULL, vwin);
2995     }
2996 }
2997 
2998 /* Called when the "install" command is used to install a function
2999    package via console or script: try to sync the local and/or remote
3000    function-package windows, if they're open. Also present the
3001    package's menu-attachment option, if any.
3002 */
3003 
maybe_update_pkgview(const char * filename,const char * pkgname,int zipfile,GtkWidget * parent)3004 void maybe_update_pkgview (const char *filename,
3005 			   const char *pkgname,
3006 			   int zipfile,
3007 			   GtkWidget *parent)
3008 {
3009     windata_t *vwin;
3010 
3011     /* update local package browser? */
3012     vwin = get_browser_for_role(FUNC_FILES, NULL);
3013     if (vwin != NULL) {
3014 	populate_filelist(vwin, NULL);
3015     }
3016 
3017     /* update remote package browser? */
3018     vwin = get_browser_for_role(REMOTE_FUNC_FILES, NULL);
3019     if (vwin != NULL && find_package_in_viewer(vwin, pkgname)) {
3020 	list_store_set_string(GTK_TREE_VIEW(vwin->listbox),
3021 			      vwin->active_var, STATUS_COLUMN,
3022 			      _("Up to date"));
3023     }
3024 
3025     if (parent != NULL) {
3026 	/* offer menu attachment if applicable */
3027 	if (zipfile) {
3028 	    gchar *gfnpath = make_gfn_path(pkgname, NULL);
3029 
3030 	    gui_function_pkg_query_register(gfnpath, parent);
3031 	    g_free(gfnpath);
3032 	} else {
3033 	    gui_function_pkg_query_register(filename, parent);
3034 	}
3035     }
3036 }
3037 
pkg_info_from_server(GtkWidget * w,windata_t * vwin)3038 void pkg_info_from_server (GtkWidget *w, windata_t *vwin)
3039 {
3040     static int idx;
3041     gchar *path, *objname = NULL;
3042     int zipfile = 0;
3043     int err = 0;
3044 
3045     tree_view_get_string(GTK_TREE_VIEW(vwin->listbox),
3046 			 vwin->active_var, 0, &objname);
3047     tree_view_get_bool(GTK_TREE_VIEW(vwin->listbox),
3048 		       vwin->active_var, ZIPFILE_COLUMN, &zipfile);
3049 
3050     path = g_strdup_printf("%sdltmp.%d", gretl_dotdir(), idx++);
3051 
3052     if (zipfile) {
3053 	gchar *zipname = g_strdup_printf("%s.zip", objname);
3054 
3055 	err = retrieve_remote_gfn_content(zipname, path);
3056 	g_free(zipname);
3057     } else {
3058 	err = retrieve_remote_function_package(objname, path);
3059     }
3060 
3061     if (err) {
3062 	show_network_error(NULL);
3063     } else {
3064 	display_function_package_data(objname, path, VIEW_PKG_INFO);
3065     }
3066 
3067     g_free(objname);
3068     g_free(path);
3069 }
3070 
3071 static gchar *
real_get_db_description(const char * fullname,const char * binname,const char * dbdir)3072 real_get_db_description (const char *fullname, const char *binname,
3073 			 const char *dbdir)
3074 {
3075     FILE *fp;
3076     char idxname[FILENAME_MAX];
3077     char *p, *descrip = NULL;
3078 
3079     if (fullname == NULL) {
3080 	gretl_build_path(idxname, dbdir, binname, NULL);
3081     } else {
3082 	strcpy(idxname, fullname);
3083     }
3084 
3085     p = strrchr(idxname, '.');
3086     if (p != NULL) {
3087 	strcpy(p, ".idx");
3088     }
3089 
3090     fp = gretl_fopen(idxname, "r");
3091 
3092     if (fp != NULL) {
3093 	char tmp[DB_DESCRIP_LEN + 32] = {0};
3094 
3095 	if (fgets(tmp, sizeof tmp, fp) != NULL) {
3096 	    if (*tmp == '#' && strlen(tmp) > 2) {
3097 		char *s = tmp + 2;
3098 
3099 		tailstrip(s);
3100 		utf8_correct(s);
3101 		descrip = g_strdup(s);
3102 	    }
3103 	}
3104 	fclose(fp);
3105     }
3106 
3107     return descrip;
3108 }
3109 
get_db_description(const char * binname)3110 gchar *get_db_description (const char *binname)
3111 {
3112     return real_get_db_description(binname, NULL, NULL);
3113 }
3114 
write_db_description(const char * binname,const char * descrip)3115 int write_db_description (const char *binname, const char *descrip)
3116 {
3117     FILE *fnew, *fbak;
3118     char idxname[FILENAME_MAX];
3119     char idxtmp[FILENAME_MAX];
3120     char tmp[72];
3121     char *p;
3122     int err = 0;
3123 
3124     strcpy(idxname, binname);
3125     p = strrchr(idxname, '.');
3126     if (p != NULL) {
3127 	strcpy(p, ".idx");
3128     }
3129 
3130     strcpy(idxtmp, idxname);
3131     p = strrchr(idxtmp, '.');
3132     if (p != NULL) {
3133 	strcpy(p, ".idxtmp");
3134     }
3135 
3136     err = copyfile(idxname, idxtmp);
3137 
3138     if (!err) {
3139 	fnew = gretl_fopen(idxname, "w");
3140 	if (fnew == NULL) {
3141 	    err = 1;
3142 	} else {
3143 	    fbak = gretl_fopen(idxtmp, "r");
3144 	    if (fbak == NULL) {
3145 		fclose(fnew);
3146 		err = 1;
3147 	    }
3148 	}
3149     }
3150 
3151     if (!err) {
3152 	const char *p = descrip;
3153 	char line[256];
3154 
3155 	while (isspace((unsigned char) *p)) {
3156 	    p++;
3157 	}
3158 	sprintf(tmp, "# %.61s\n", p);
3159 	tailstrip(tmp);
3160 	fprintf(fnew, "%s\n", tmp);
3161 	while (fgets(line, sizeof line, fbak)) {
3162 	    if (*line != '#') {
3163 		fputs(line, fnew);
3164 	    }
3165 	}
3166 	fclose(fnew);
3167 	fclose(fbak);
3168 	gretl_remove(idxtmp);
3169     }
3170 
3171     return err;
3172 }
3173 
3174 static int
read_db_files_in_dir(GDir * dir,int dbtype,const char * path,GtkListStore * store,GtkTreeIter * iter)3175 read_db_files_in_dir (GDir *dir, int dbtype, const char *path,
3176 		      GtkListStore *store, GtkTreeIter *iter)
3177 {
3178     const gchar *fname;
3179     gchar *name, *descrip;
3180     int len, ndb = 0;
3181 
3182     while ((fname = g_dir_read_name(dir)) != NULL) {
3183 	len = strlen(fname);
3184 	if (!g_ascii_strcasecmp(fname + len - 4, ".bin")) {
3185 	    name = g_strndup(fname, len - 4);
3186 	    descrip = real_get_db_description(NULL, fname, path);
3187 	    if (name != NULL && descrip != NULL) {
3188 #if DB_SEARCH_DEBUG
3189 		fprintf(stderr, "  found '%s'\n", name);
3190 #endif
3191 		gtk_list_store_append(store, iter);
3192 		gtk_list_store_set(store, iter,
3193 				   COL_DBNAME, name,
3194 				   COL_DBINFO, descrip,
3195 				   COL_DBPATH, path, -1);
3196 		ndb++;
3197 	    }
3198 	    g_free(name);
3199 	    g_free(descrip);
3200 	}
3201     }
3202 
3203     return ndb;
3204 }
3205 
get_local_object_status(const char * fname,int role,const char ** status,time_t remtime)3206 static void get_local_object_status (const char *fname,
3207 				     int role,
3208 				     const char **status,
3209 				     time_t remtime)
3210 {
3211     char fullname[MAXLEN];
3212     struct stat fbuf;
3213     char **dirs;
3214     SearchType stype;
3215     int found = 0;
3216     int i, n_dirs;
3217     int err = 0;
3218 
3219     if (role == REMOTE_DB) {
3220 	stype = DB_SEARCH;
3221     } else if (role == REMOTE_DATA_PKGS) {
3222 	stype = DATA_SEARCH;
3223     } else if (role == REMOTE_FUNC_FILES) {
3224 	stype = FUNCS_SEARCH;
3225     } else {
3226 	*status = N_("Unknown: access error");
3227 	return;
3228     }
3229 
3230     dirs = get_plausible_search_dirs(stype, &n_dirs);
3231 
3232     for (i=0; i<n_dirs; i++) {
3233 	gretl_build_path(fullname, dirs[i], fname, NULL);
3234 	errno = 0;
3235 	if (gretl_stat(fullname, &fbuf) == 0) {
3236 	    found = 1;
3237 	    break;
3238 	} else if (errno != ENOENT) {
3239 	    err = 1;
3240 	    break;
3241 	}
3242     }
3243 
3244     strings_array_free(dirs, n_dirs);
3245 
3246     if (found) {
3247 	double dt;
3248 
3249 	dt = difftime(remtime, fbuf.st_ctime);
3250 	if (dt > 360) {
3251 	    dt = difftime(remtime, fbuf.st_mtime);
3252 	}
3253 	if (dt > 360) {
3254 	    *status = N_("Not up to date");
3255 	} else {
3256 	    *status = N_("Up to date");
3257 	}
3258     } else if (err) {
3259 	*status = N_("Unknown: access error");
3260     } else {
3261 	*status = N_("Not installed");
3262     }
3263 }
3264 
read_remote_filetime(char * line,char * fname,time_t * date,char * tbuf)3265 static int read_remote_filetime (char *line, char *fname,
3266 				 time_t *date, char *tbuf)
3267 {
3268     char month[4], hrs[9];
3269     int mday = -1, yr = -1, mon = -1;
3270     const char *months[] = {
3271 	"Jan", "Feb", "Mar", "Apr",
3272 	"May", "Jun", "Jul", "Aug",
3273 	"Sep", "Oct", "Nov", "Dec"
3274     };
3275     int i;
3276 
3277     /* We're expecting a string of the form:
3278 
3279        "<bytes> <day> <mon> <mday> 00:00:00 <year> <filename>"
3280 
3281        e.g.
3282 
3283        "   2719 Foo Dec 17 00:00:00 2010     addlist.gfn"
3284 
3285        where <mon> is 3-letter month, <mday> is 2 digits,
3286        and <year> is 4-digit year; in this context we actually
3287        discard the first two fields, @bytes and @day.
3288     */
3289 
3290     if (sscanf(line, "%*s%*s%3s%2d%8s%4d%31s",
3291 	       month, &mday, hrs, &yr, fname) != 5) {
3292 	return 1;
3293     }
3294 
3295     for (i=0; i<12; i++) {
3296 	if (!strcmp(month, months[i])) {
3297 	    mon = i;
3298 	}
3299     }
3300 
3301     if (mon < 0 || mday < 1 || yr < 2000) {
3302 	return 1;
3303     }
3304 
3305     if (date != NULL) {
3306 	struct tm mytime;
3307 
3308 	hrs[2] = 0;
3309 
3310 	mytime.tm_sec = 0;
3311 	mytime.tm_min = 0;
3312 	mytime.tm_wday = 0;
3313 	mytime.tm_yday = 0;
3314 	mytime.tm_isdst = -1;
3315 	mytime.tm_hour = atoi(hrs);
3316 	mytime.tm_year = yr - 1900;
3317 	mytime.tm_mday = mday;
3318 	mytime.tm_mon = mon;
3319 
3320 	*date = mktime(&mytime);
3321     }
3322 
3323     if (tbuf != NULL) {
3324 	sprintf(tbuf, "%d-%02d-%02d", yr, mon + 1, mday);
3325     }
3326 
3327     return 0;
3328 }
3329 
3330 /* below: mechanism for tucking individual databases under a 'twisty',
3331    when there's a large number of databases from a single source.
3332 */
3333 
get_source_string(char * src,const char * s)3334 static char *get_source_string (char *src, const char *s)
3335 {
3336     char *p;
3337 
3338     *src = 0;
3339     strncat(src, s, 95);
3340 
3341     p = strchr(src, '(');
3342     if (p == NULL) {
3343 	p = strstr(src, "--");
3344     }
3345     if (p != NULL) {
3346 	*p = '\0';
3347     }
3348     tailstrip(src);
3349 
3350     return src;
3351 }
3352 
3353 struct src_info {
3354     int start;
3355     int ndb;
3356 };
3357 
3358 static struct src_info *dbsrc;
3359 static int n_src;
3360 
push_src_info(int start,int ndb)3361 static int push_src_info (int start, int ndb)
3362 {
3363     struct src_info *tmp;
3364 
3365     tmp = realloc(dbsrc, (n_src + 1) * sizeof *tmp);
3366     if (tmp == NULL) {
3367 	return E_ALLOC;
3368     }
3369 
3370     dbsrc = tmp;
3371     dbsrc[n_src].start = start;
3372     dbsrc[n_src].ndb = ndb;
3373     n_src++;
3374 
3375     return 0;
3376 }
3377 
get_ndbs(int lineno)3378 static int get_ndbs (int lineno)
3379 {
3380     int i;
3381 
3382     for (i=0; i<n_src; i++) {
3383 	if (dbsrc[i].start == lineno) {
3384 	    return dbsrc[i].ndb;
3385 	}
3386     }
3387 
3388     return 1;
3389 }
3390 
free_src_info(void)3391 static void free_src_info (void)
3392 {
3393     free(dbsrc);
3394     dbsrc = NULL;
3395     n_src = 0;
3396 }
3397 
populate_remote_db_list(windata_t * vwin)3398 gint populate_remote_db_list (windata_t *vwin)
3399 {
3400     GtkTreeStore *store;
3401     GtkTreeIter iter, child_iter;
3402     char *getbuf = NULL;
3403     char line[1024];
3404     char fname[32];
3405     char src[96], srcbak[96];
3406     const char *status;
3407     gchar *row[3];
3408     time_t remtime;
3409     int start, parent, kids;
3410     int i, ndb, err = 0;
3411 
3412     err = list_remote_dbs(&getbuf);
3413     if (err) {
3414 	show_network_error(NULL);
3415 	free(getbuf);
3416 	return err;
3417     }
3418 
3419     i = 0;
3420     ndb = start = 0;
3421     src[0] = srcbak[0] = '\0';
3422 
3423     /* first pass: figure "parentage" of databases */
3424 
3425     bufgets_init(getbuf);
3426 
3427     while (bufgets(line, sizeof line, getbuf)) {
3428 	if (strstr(line, "idx")) {
3429 	    continue;
3430 	}
3431 	if (read_remote_filetime(line, fname, &remtime, NULL)) {
3432 	    continue;
3433 	}
3434 	if (bufgets(line, sizeof line, getbuf)) {
3435 	    get_source_string(src, line + 2);
3436 	    if (strcmp(src, srcbak)) {
3437 		if (ndb > 3) {
3438 		    push_src_info(start, ndb);
3439 		}
3440 		start = i;
3441 		ndb = 1;
3442 	    } else {
3443 		ndb++;
3444 	    }
3445 	    strcpy(srcbak, src);
3446 	}
3447 	i++;
3448     }
3449 
3450     bufgets_finalize(getbuf);
3451 
3452     if (i == 0) {
3453 	errbox(_("No database files found"));
3454 	free_src_info();
3455 	free(getbuf);
3456 	return 1;
3457     }
3458 
3459     /* second pass: insert databases into tree view */
3460 
3461     store = GTK_TREE_STORE(gtk_tree_view_get_model
3462 			   (GTK_TREE_VIEW(vwin->listbox)));
3463     gtk_tree_store_clear(store);
3464     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3465 
3466     i = 0;
3467     parent = kids = 0;
3468 
3469     bufgets_init(getbuf);
3470 
3471     while (bufgets(line, sizeof line, getbuf)) {
3472 	if (strstr(line, "idx")) {
3473 	    continue;
3474 	}
3475 	if (read_remote_filetime(line, fname, &remtime, NULL)) {
3476 	    continue;
3477 	}
3478 
3479 	status = "";
3480 	get_local_object_status(fname, vwin->role, &status, remtime);
3481 	row[0] = strip_extension(fname);
3482 	row[1] = NULL;
3483 	row[2] = _(status);
3484 
3485 	if (bufgets(line, sizeof line, getbuf)) {
3486 	    tailstrip(line);
3487 	    utf8_correct(line);
3488 	    row[1] = line + 2;
3489 	    ndb = get_ndbs(i);
3490 	    if (ndb > 1) {
3491 		get_source_string(src, row[1]);
3492 		parent = 1;
3493 		kids = ndb;
3494 	    }
3495 	}
3496 	if (parent) {
3497 	    /* header for child databases */
3498 	    gtk_tree_store_append(store, &iter, NULL);
3499 	    gtk_tree_store_set(store, &iter, 0, "", 1, src, -1);
3500 	    parent = 0;
3501 	}
3502 	if (kids > 0) {
3503 	    /* insert child under heading */
3504 	    gtk_tree_store_insert_before(store, &child_iter,
3505 					 &iter, NULL);
3506 	    gtk_tree_store_set(store, &child_iter, 0, row[0],
3507 			       1, row[1], 2, row[2], -1);
3508 	    kids--;
3509 	} else {
3510 	    /* insert at top level */
3511 	    gtk_tree_store_append(store, &iter, NULL);
3512 	    gtk_tree_store_set(store, &iter, 0, row[0], 1, row[1],
3513 			       2, row[2], -1);
3514 	}
3515 	i++;
3516     }
3517 
3518     bufgets_finalize(getbuf);
3519     free(getbuf);
3520     free_src_info();
3521 
3522     if (!err) {
3523 	db_drag_connect(vwin, GRETL_REMOTE_DB_PTR);
3524     }
3525 
3526     return err;
3527 }
3528 
populate_dbnomics_provider_list(windata_t * vwin)3529 gint populate_dbnomics_provider_list (windata_t *vwin)
3530 {
3531     gretl_array *A;
3532     GtkListStore *store;
3533     GtkTreeIter iter;
3534     int i, ndb = 0;
3535     int err = 0;
3536 
3537     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox)));
3538     gtk_list_store_clear(store);
3539     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3540 
3541     /* call dbnomics package to get listing */
3542     A = dbnomics_get_providers_call(&err);
3543     if (err) {
3544 	return err;
3545     } else {
3546 	gretl_bundle *b;
3547 	char *code, *name;
3548 	int n;
3549 
3550 	n = gretl_array_get_length(A);
3551 	for (i=0; i<n; i++) {
3552 	    b = gretl_array_get_bundle(A, i);
3553 	    code = (char *) gretl_bundle_get_string(b, "code", &err);
3554 	    name = (char *) gretl_bundle_get_string(b, "name", &err);
3555 	    if (!err) {
3556 		gtk_list_store_append(store, &iter);
3557 		gtk_list_store_set(store, &iter,
3558 				   COL_DBNAME, code,
3559 				   COL_DBINFO, name, -1);
3560 		ndb++;
3561 	    }
3562 	}
3563 	gretl_array_destroy(A);
3564     }
3565 
3566     if (ndb == 0) {
3567 	errbox(_("No database files found"));
3568 	err = 1;
3569     }
3570 
3571     return err;
3572 }
3573 
3574 struct dbn_pager {
3575     int offset;  /* offset to pass to dbnomics */
3576     int n;       /* number of datasets or series in window */
3577     int ntotal;  /* total, as reported by dbnomics */
3578     int chunk;   /* limit to number of items to grab */
3579 };
3580 
3581 #define DBN_DSETS_CHUNK 40
3582 #define DBN_SERIES_CHUNK 100
3583 
dbn_pager_new(windata_t * vwin)3584 static struct dbn_pager *dbn_pager_new (windata_t *vwin)
3585 {
3586     struct dbn_pager *p = malloc(sizeof *p);
3587 
3588     if (p != NULL) {
3589 	p->offset = 0;
3590 	p->n = 0;
3591 	p->ntotal = 0;
3592 	if (vwin->role == DBNOMICS_DB) {
3593 	    p->chunk = DBN_DSETS_CHUNK;
3594 	} else {
3595 	    p->chunk = DBN_SERIES_CHUNK;
3596 	}
3597 	vwin->data = p;
3598     }
3599 
3600     return p;
3601 }
3602 
dbnomics_pager_call(GtkWidget * button,windata_t * vwin)3603 void dbnomics_pager_call (GtkWidget *button, windata_t *vwin)
3604 {
3605     int action = widget_get_int(button, "action");
3606     struct dbn_pager *pgr = vwin->data;
3607     int oldoff = pgr->offset;
3608     int newoff;
3609 
3610     /* action: 1-based enumeration; see make_files_toolbar()
3611        in datafiles.c
3612     */
3613 
3614     if (action == 1) {
3615 	/* first */
3616 	pgr->offset = 0;
3617     } else if (action == 2) {
3618 	/* previous */
3619 	newoff = pgr->offset - pgr->chunk;
3620 	pgr->offset = newoff < 0 ? 0 : newoff;
3621     } else if (action == 3) {
3622 	/* next */
3623 	int maxoff = pgr->ntotal - 1;
3624 
3625 	newoff = pgr->offset + pgr->chunk;
3626 	pgr->offset = newoff > maxoff ? maxoff : newoff;
3627     } else if (action == 4) {
3628 	/* last */
3629 	pgr->offset = pgr->ntotal - pgr->chunk + 1;
3630     }
3631 
3632     if (pgr->offset != oldoff) {
3633 	if (vwin->role == DBNOMICS_DB) {
3634 	    populate_dbnomics_dataset_list(vwin, NULL);
3635 	} else {
3636 	    populate_dbnomics_series_list(vwin, NULL);
3637 	}
3638 	listbox_select_first(vwin);
3639     }
3640 }
3641 
set_dbn_pager_status(windata_t * vwin)3642 static void set_dbn_pager_status (windata_t *vwin)
3643 {
3644     GtkWidget *b1 = g_object_get_data(G_OBJECT(vwin->mbar), "first-button");
3645     GtkWidget *b2 = g_object_get_data(G_OBJECT(vwin->mbar), "prev-button");
3646     GtkWidget *b3 = g_object_get_data(G_OBJECT(vwin->mbar), "next-button");
3647     GtkWidget *b4 = g_object_get_data(G_OBJECT(vwin->mbar), "last-button");
3648     struct dbn_pager *pgr = vwin->data;
3649     int first = pgr->offset + 1;
3650     int last = pgr->offset + pgr->n;
3651     gchar *tmp;
3652 
3653     gtk_widget_set_sensitive(b1, pgr->offset > 0);
3654     gtk_widget_set_sensitive(b2, pgr->offset > 0);
3655     gtk_widget_set_sensitive(b3, last < pgr->ntotal);
3656     gtk_widget_set_sensitive(b4, last < pgr->ntotal);
3657 
3658     if (vwin->role == DBNOMICS_DB) {
3659 	tmp = g_strdup_printf(_("showing datasets %d-%d of %d"),
3660 			      first, last, pgr->ntotal);
3661     } else {
3662 	tmp = g_strdup_printf(_("showing series %d-%d of %d"),
3663 			      first, last, pgr->ntotal);
3664     }
3665 
3666     gtk_label_set_text(GTK_LABEL(vwin->status), tmp);
3667     while (gtk_events_pending()) {
3668 	gtk_main_iteration();
3669     }
3670     g_free(tmp);
3671 }
3672 
3673 /* list the datasets available for a given provider */
3674 
populate_dbnomics_dataset_list(windata_t * vwin,gpointer p)3675 gint populate_dbnomics_dataset_list (windata_t *vwin, gpointer p)
3676 {
3677     gchar *provider = (gchar *) p;
3678     gretl_array *C, *N;
3679     gretl_bundle *b;
3680     char *code, *name;
3681     GtkListStore *store;
3682     GtkTreeIter iter;
3683     struct dbn_pager *pgr;
3684     int starting = 1;
3685     int i, imin, imax;
3686     int err = 0;
3687 
3688     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox)));
3689     gtk_list_store_clear(store);
3690     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3691 
3692     if (vwin->data == NULL) {
3693 	/* starting: we don't have a pager yet */
3694 	pgr = dbn_pager_new(vwin);
3695 	b = dbnomics_dataset_list(provider, &err);
3696 	if (err) {
3697 	    return err;
3698 	}
3699     } else {
3700 	b = g_object_get_data(G_OBJECT(vwin->listbox), "dset-list");
3701 	provider = g_object_get_data(G_OBJECT(vwin->listbox), "provider");
3702 	pgr = vwin->data;
3703 	starting = 0;
3704     }
3705 
3706     if (!err) {
3707 	C = gretl_bundle_get_array(b, "codes", &err);
3708 	N = gretl_bundle_get_array(b, "names", &err);
3709 	if (!err && starting) {
3710 	    pgr->ntotal = gretl_array_get_length(C);
3711 	    if (pgr->ntotal == 0) {
3712 		errbox(_("No datasets were found"));
3713 		err = 1;
3714 	    }
3715 	}
3716     }
3717 
3718     if (err) {
3719 	return err;
3720     }
3721 
3722     if (pgr->ntotal <= pgr->chunk) {
3723 	/* just display everything */
3724 	imin = 0;
3725 	imax = pgr->ntotal;
3726     } else {
3727 	/* display the first so many after offset */
3728 	imin = pgr->offset;
3729 	imax = imin + pgr->chunk;
3730 	imax = imax > pgr->ntotal ? pgr->ntotal : imax;
3731     }
3732 
3733     pgr->n = imax - imin;
3734 
3735     for (i=imin; i<imax; i++) {
3736 	code = gretl_array_get_element(C, i, NULL, &err);
3737 	name = gretl_array_get_element(N, i, NULL, &err);
3738 	if (!err) {
3739 	    gtk_list_store_append(store, &iter);
3740 	    gtk_list_store_set(store, &iter,
3741 			       COL_DBNAME, code,
3742 			       COL_DBINFO, name, -1);
3743 	}
3744     }
3745 
3746     if (pgr->ntotal <= pgr->chunk) {
3747 	/* no need to keep the dataset-list bundle */
3748 	gretl_bundle_destroy(b);
3749     } else if (starting) {
3750 	g_object_set_data_full(G_OBJECT(vwin->listbox), "dset-list", b,
3751 			       (GDestroyNotify) gretl_bundle_destroy);
3752     }
3753 
3754     /* set and show status */
3755     set_dbn_pager_status(vwin);
3756     if (starting) {
3757 	/* and make the provider name available downstream */
3758 	g_object_set_data_full(G_OBJECT(vwin->listbox), "provider",
3759 			       provider, g_free);
3760     }
3761 
3762     return err;
3763 }
3764 
populate_dbnomics_series_list(windata_t * vwin,gpointer p)3765 gint populate_dbnomics_series_list (windata_t *vwin, gpointer p)
3766 {
3767     gchar *dsref = (gchar *) p;
3768     gretl_array *A = NULL;
3769     gretl_bundle *b;
3770     char *s, *prov, *dset;
3771     char *code, *name;
3772     GtkListStore *store;
3773     GtkTreeIter iter;
3774     struct dbn_pager *pgr;
3775     int starting = 1;
3776     int alen = 0;
3777     int i, err = 0;
3778 
3779     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox)));
3780     gtk_list_store_clear(store);
3781     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3782 
3783     if (vwin->data == NULL) {
3784 	/* starting: we don't have a pager yet */
3785 	pgr = dbn_pager_new(vwin);
3786     } else {
3787 	dsref = g_object_get_data(G_OBJECT(vwin->listbox), "path");
3788 	pgr = vwin->data;
3789 	starting = 0;
3790     }
3791 
3792     s = strchr(dsref, '/');
3793     dset = g_strdup(s + 1);
3794     prov = g_strndup(dsref, s - dsref);
3795 
3796     /* Note: the length of the retrieved array, which we write into
3797        @alen, may be less (perhaps a lot less) than the "num_found"
3798        field that we access below, since the latter records the
3799        total number of series, regardless of the max number set on
3800        the dbnomics query.
3801     */
3802 
3803     A = dbnomics_probe_series(prov, dset, pgr->chunk, pgr->offset, &err);
3804     if (!err) {
3805 	alen = gretl_array_get_length(A);
3806 	if (alen == 0) {
3807 	    errbox(_("No series were found"));
3808 	    err = 1;
3809 	}
3810     }
3811 
3812     if (err) {
3813 	return err;
3814     }
3815 
3816     pgr->n = 0;
3817     for (i=0; i<alen; i++) {
3818 	b = gretl_array_get_bundle(A, i);
3819 	if (i == 0) {
3820 	    pgr->ntotal = gretl_bundle_get_int(b, "num_found", NULL);
3821 	}
3822 	code = (char *) gretl_bundle_get_string(b, "code", &err);
3823 	name = (char *) gretl_bundle_get_string(b, "name", &err);
3824 	if (!err) {
3825 	    gtk_list_store_append(store, &iter);
3826 	    gtk_list_store_set(store, &iter,
3827 			       COL_DBNAME, code,
3828 			       COL_DBINFO, name, -1);
3829 	    pgr->n += 1;
3830 	}
3831     }
3832 
3833     gretl_array_destroy(A); /* we're done with this */
3834 
3835     if (pgr->n == 0) {
3836 	errbox(_("No series were found"));
3837 	err = 1;
3838     } else {
3839 	/* set and show status */
3840 	set_dbn_pager_status(vwin);
3841 	if (starting) {
3842 	    /* and make the dataset 'path' available downstream */
3843 	    g_object_set_data_full(G_OBJECT(vwin->listbox), "path",
3844 				   dsref, g_free);
3845 	}
3846     }
3847 
3848     return err;
3849 }
3850 
get_remote_addon_info(xmlNodePtr node,xmlDocPtr doc,char ** S,const char * minvstr)3851 static int get_remote_addon_info (xmlNodePtr node, xmlDocPtr doc,
3852 				  char **S, const char *minvstr)
3853 {
3854     xmlNodePtr cur = node->xmlChildrenNode;
3855     int err = 0;
3856 
3857     while (cur != NULL) {
3858 	if (!xmlStrcmp(cur->name, (XUC) "version")) {
3859 	    gretl_xml_node_get_trimmed_string(cur, doc, &S[1]);
3860 	} else if (!xmlStrcmp(cur->name, (XUC) "date")) {
3861 	    gretl_xml_node_get_trimmed_string(cur, doc, &S[2]);
3862 	} else if (!xmlStrcmp(cur->name, (XUC) "description")) {
3863 	    gretl_xml_node_get_trimmed_string(cur, doc, &S[4]);
3864 	}
3865 	cur = cur->next;
3866     }
3867 
3868     if (S[1] == NULL || S[2] == NULL || S[4] == NULL) {
3869 	err = E_DATA;
3870     } else {
3871 	char *path = gretl_addon_get_path(S[0]);
3872 	int minver = gretl_version_number(minvstr);
3873 
3874 	if (path != NULL) {
3875 	    S[3] = installed_addon_status_string(path, S[1], minver);
3876 	    free(path);
3877 	} else {
3878 	    S[3] = gretl_strdup(_("Not installed"));
3879 	}
3880     }
3881 
3882     return err;
3883 }
3884 
populate_remote_addons_list(windata_t * vwin)3885 gint populate_remote_addons_list (windata_t *vwin)
3886 {
3887     xmlDocPtr doc;
3888     xmlNodePtr node = NULL;
3889     char *getbuf = NULL;
3890     int n = 0, err = 0;
3891 
3892     err = query_sourceforge("/addons-data/addons.xml", &getbuf);
3893     if (err) {
3894 	show_network_error(NULL);
3895 	free(getbuf);
3896 	return err;
3897     }
3898 
3899 #if 0
3900     fprintf(stderr, "populate_remote_addons_list: got XML:\n");
3901     fprintf(stderr, "'%s'\n", getbuf);
3902 #endif
3903 
3904     xmlKeepBlanksDefault(0);
3905 
3906     doc = xmlParseMemory(getbuf, strlen(getbuf));
3907     if (doc == NULL) {
3908 	err = E_DATA;
3909     } else {
3910 	node = xmlDocGetRootElement(doc);
3911 	if (node == NULL || xmlStrcmp(node->name, (XUC) "gretl-addons")) {
3912 	    err = E_DATA;
3913 	}
3914     }
3915 
3916     if (!err) {
3917 	GtkListStore *store;
3918 	GtkTreeIter iter;
3919 	char *S[5] = { NULL };
3920 	char *minvstr = NULL;
3921 	int i;
3922 
3923 	store = GTK_LIST_STORE(gtk_tree_view_get_model
3924 			       (GTK_TREE_VIEW(vwin->listbox)));
3925 	gtk_list_store_clear(store);
3926 	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3927 	node = node->xmlChildrenNode;
3928 
3929 	while (node != NULL && !err) {
3930 	    if (!xmlStrcmp(node->name, (XUC) "gretl-addon")) {
3931 		gretl_xml_get_prop_as_string(node, "name", &S[0]);
3932 		gretl_xml_get_prop_as_string(node, "minver", &minvstr);
3933 		if (S[0] == NULL) {
3934 		    err = E_DATA;
3935 		} else {
3936 		    err = get_remote_addon_info(node, doc, S, minvstr);
3937 		    if (!err) {
3938 			gtk_list_store_append(store, &iter);
3939 			gtk_list_store_set(store, &iter,
3940 					   0, S[0], 1, S[1],
3941 					   2, S[2], 3, S[3],
3942 					   4, S[4], -1);
3943 			for (i=0; i<5; i++) {
3944 			    free(S[i]);
3945 			    S[i] = NULL;
3946 			}
3947 			n++;
3948 		    }
3949 		}
3950 	    }
3951 	    node = node->next;
3952 	}
3953     }
3954 
3955     if (err) {
3956 	gui_errmsg(err);
3957     } else if (n == 0) {
3958 	warnbox(_("No function packages found"));
3959 	err = 1;
3960     }
3961 
3962     if (doc != NULL) {
3963 	xmlFreeDoc(doc);
3964     }
3965 
3966     free(getbuf);
3967 
3968     return err;
3969 }
3970 
check_gfn_drag_connection(windata_t * vwin)3971 static void check_gfn_drag_connection (windata_t *vwin)
3972 {
3973     int dc = widget_get_int(vwin->main, "drag-connected");
3974 
3975     if (!dc) {
3976 	db_drag_connect(vwin, GRETL_REMOTE_FNPKG_PTR);
3977 	widget_set_int(vwin->main, "drag-connected", 1);
3978     }
3979 }
3980 
is_depends_line(const char * fname,const char * line,GtkListStore * store,GtkTreeIter * iter)3981 static int is_depends_line (const char *fname,
3982 			    const char *line,
3983 			    GtkListStore *store,
3984 			    GtkTreeIter *iter)
3985 {
3986     if (!strncmp(line, "# depends(", 10)) {
3987 	gchar *s = g_strdup(strchr(line, ')') + 1);
3988 
3989 	g_strchomp(g_strchug(s));
3990 	gtk_list_store_set(store, iter, 7, s, -1);
3991 	g_free(s);
3992 	return 1;
3993     } else {
3994 	return 0;
3995     }
3996 }
3997 
3998 /* Fill a list box with name, version number, author,
3999    and short description of function packages, retrieved
4000    from server.
4001 */
4002 
populate_remote_func_list(windata_t * vwin,int filter)4003 gint populate_remote_func_list (windata_t *vwin, int filter)
4004 {
4005     GtkListStore *store;
4006     GtkTreeIter iter;
4007     char *getbuf = NULL;
4008     char line[1024];
4009     char fname[128];
4010     char basename[32];
4011     const char *status;
4012     time_t remtime;
4013     int n, err = 0;
4014 
4015     err = list_remote_function_packages(&getbuf, filter);
4016     if (err) {
4017 	show_network_error(NULL);
4018 	free(getbuf);
4019 	return err;
4020     }
4021 
4022 #if 0
4023     fprintf(stderr, "getbuf: '%s'\n", getbuf);
4024 #endif
4025 
4026     store = GTK_LIST_STORE(gtk_tree_view_get_model
4027 			   (GTK_TREE_VIEW(vwin->listbox)));
4028     gtk_list_store_clear(store);
4029     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
4030 
4031     n = 0;
4032     bufgets_init(getbuf);
4033 
4034     while (bufgets(line, sizeof line, getbuf)) {
4035 	char *descrip = NULL;
4036 	char *version = NULL;
4037 	char *author = NULL;
4038 	char datestr[12];
4039 	gboolean zipfile;
4040 
4041 	if (is_depends_line(fname, line, store, &iter)) {
4042 	    continue;
4043 	}
4044 
4045 	if (read_remote_filetime(line, fname, &remtime, datestr)) {
4046 	    continue;
4047 	}
4048 
4049 	strcpy(basename, fname);
4050 	strip_extension(basename);
4051 
4052 	zipfile = has_suffix(fname, ".zip");
4053 	if (zipfile) {
4054 	    /* local status: look for PKG/PKG.gfn, not PKG.zip */
4055 	    sprintf(fname, "%s%c%s.gfn", basename, SLASH, basename);
4056 	}
4057 
4058 	status = "";
4059 	get_local_object_status(fname, vwin->role, &status, remtime);
4060 
4061 	if (bufgets(line, sizeof line, getbuf)) {
4062 	    tailstrip(line);
4063 	    utf8_correct(line);
4064 	    descrip = gretl_strdup(line + 2);
4065 	    maybe_ellipsize_string(descrip, 48);
4066 	}
4067 
4068 	if (bufgets(line, sizeof line, getbuf)) {
4069 	    tailstrip(line);
4070 	    version = gretl_strdup(line + 2);
4071 	}
4072 
4073 	if (bufgets(line, sizeof line, getbuf)) {
4074 	    tailstrip(line);
4075 	    author = gretl_strdup(line + 2);
4076 	    maybe_ellipsize_string(author, 26);
4077 	}
4078 
4079 	if (descrip != NULL && version != NULL && author != NULL) {
4080 	    gtk_list_store_append(store, &iter);
4081 	    gtk_list_store_set(store, &iter,
4082 			       0, basename,
4083 			       1, version,
4084 			       2, datestr,
4085 			       3, author,
4086 			       4, descrip,
4087 			       5, _(status),
4088 			       6, zipfile,
4089 			       -1);
4090 	    n++;
4091 	}
4092 
4093 	free(descrip);
4094 	free(version);
4095 	free(author);
4096     }
4097 
4098     bufgets_finalize(getbuf);
4099     free(getbuf);
4100 
4101     if (n == 0) {
4102 	warnbox(_("No function packages found"));
4103 	err = 1;
4104     }
4105 
4106     if (!err) {
4107 	check_gfn_drag_connection(vwin);
4108     }
4109 
4110     return err;
4111 }
4112 
4113 /* Fill a list box with names and short descriptions
4114    of data file packages, retrieved from server.
4115 */
4116 
populate_remote_data_pkg_list(windata_t * vwin)4117 gint populate_remote_data_pkg_list (windata_t *vwin)
4118 {
4119     GtkListStore *store;
4120     GtkTreeIter iter;
4121     char *getbuf = NULL;
4122     char line[256];
4123     char fname[32];
4124     char tstr[16];
4125     char *descrip;
4126     int n, err = 0;
4127 
4128     err = list_remote_data_packages(&getbuf);
4129 
4130     if (err) {
4131 	show_network_error(NULL);
4132 	free(getbuf);
4133 	return err;
4134     }
4135 
4136     store = GTK_LIST_STORE(gtk_tree_view_get_model
4137 			   (GTK_TREE_VIEW(vwin->listbox)));
4138     gtk_list_store_clear(store);
4139     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
4140 
4141     n = 0;
4142     bufgets_init(getbuf);
4143 
4144     while (bufgets(line, sizeof line, getbuf)) {
4145 	descrip = NULL;
4146 	*tstr = '\0';
4147 
4148 	if (read_remote_filetime(line, fname, NULL, tstr)) {
4149 	    continue;
4150 	}
4151 
4152 	strip_extension(fname);
4153 
4154 	if (bufgets(line, sizeof line, getbuf)) {
4155 	    tailstrip(line);
4156 	    utf8_correct(line);
4157 	    descrip = gretl_strdup(line + 2);
4158 	}
4159 
4160 	if (descrip == NULL) {
4161 	    descrip = gretl_strdup("");
4162 	}
4163 
4164 	gtk_list_store_append(store, &iter);
4165 	gtk_list_store_set(store, &iter,
4166 			   0, fname,
4167 			   1, descrip,
4168 			   2, tstr,
4169 			   -1);
4170 
4171 	free(descrip);
4172 	n++;
4173     }
4174 
4175     bufgets_finalize(getbuf);
4176     free(getbuf);
4177 
4178     if (n == 0) {
4179 	warnbox(_("No data packages found"));
4180 	err = 1;
4181     }
4182 
4183     return err;
4184 }
4185 
maybe_replace_db_path(const char * name,GtkTreeIter * iter,GtkTreeIter * iprev,GtkTreeModel * mod)4186 static int maybe_replace_db_path (const char *name,
4187 				  GtkTreeIter *iter,
4188 				  GtkTreeIter *iprev,
4189 				  GtkTreeModel *mod)
4190 {
4191     gchar *db, *dbprev;
4192     gchar *path, *pathprev;
4193     struct stat buf, bufprev;
4194     int err = 0, ret = 0;
4195 
4196     fprintf(stderr, "databases: found a duplicate of %s\n", name);
4197 
4198     gtk_tree_model_get(mod, iter, 2, &path, -1);
4199     gtk_tree_model_get(mod, iprev, 2, &pathprev, -1);
4200     /* formulate full names of the two .bin files */
4201     db = g_strdup_printf("%s%c%s.bin", path, SLASH, name);
4202     dbprev = g_strdup_printf("%s%c%s.bin", pathprev, SLASH, name);
4203 
4204     err = gretl_stat(db, &buf);
4205     if (!err) {
4206 	err = gretl_stat(dbprev, &bufprev);
4207     }
4208     if (!err && buf.st_mtime > bufprev.st_mtime) {
4209 	/* @db is newer than @dbprev, so replace path */
4210 	fprintf(stderr, " using newer version in %s\n", path);
4211 	fprintf(stderr, " masking version in %s\n", pathprev);
4212 	gtk_list_store_set(GTK_LIST_STORE(mod), iprev, 2, path, -1);
4213 	ret = 1;
4214     } else {
4215 	fprintf(stderr, " keeping version in %s\n", pathprev);
4216 	fprintf(stderr, " ignoring version in %s\n", path);
4217     }
4218 
4219     g_free(path);
4220     g_free(pathprev);
4221     g_free(db);
4222     g_free(dbprev);
4223 
4224     return ret;
4225 }
4226 
4227 /* Purge any duplicates from the list of database files to
4228    display -- in case of duplicates we keep the newer file
4229    as assessed by stat's st_mtime.
4230 */
4231 
maybe_prune_db_list(GtkTreeView * tview,int * pndb)4232 static void maybe_prune_db_list (GtkTreeView *tview,
4233 				 int *pndb)
4234 {
4235     char **S;
4236     GtkTreeModel *mod;
4237     GtkListStore *store;
4238     GtkTreeIter iter;
4239     GtkTreeIter *icpy;
4240     int ndb, i = 0;
4241 
4242     mod = gtk_tree_view_get_model(tview);
4243     store = GTK_LIST_STORE(mod);
4244     if (!gtk_tree_model_get_iter_first(mod, &iter)) {
4245 	return;
4246     }
4247 
4248     ndb = *pndb;
4249     S = strings_array_new(ndb);
4250     if (S == NULL) {
4251 	return;
4252     }
4253     icpy = malloc(ndb * sizeof *icpy);
4254     if (icpy == NULL) {
4255 	goto bailout;
4256     }
4257 
4258     while (1) {
4259 	int j, drop = 0;
4260 
4261 	gtk_tree_model_get(mod, &iter, 0, &S[i], -1);
4262 	icpy[i] = iter;
4263 	for (j=0; j<i; j++) {
4264 	    if (S[j] != NULL && !strcmp(S[i], S[j])) {
4265 		/* found a duplicate */
4266 		drop = 1;
4267 		*pndb -= 1;
4268 		maybe_replace_db_path(S[j], &iter, &icpy[j], mod);
4269 		gtk_list_store_remove(store, &iter);
4270 		iter = icpy[i-1]; /* back up one row */
4271 		g_free(S[i]);
4272 		S[i] = NULL;
4273 		break;
4274 	    }
4275 	}
4276 	if (!gtk_tree_model_iter_next(mod, &iter)) {
4277 	    break;
4278 	}
4279 	if (!drop) {
4280 	    i++;
4281 	}
4282     }
4283 
4284  bailout:
4285 
4286     for (i=0; i<ndb; i++) {
4287 	g_free(S[i]);
4288     }
4289     free(S);
4290     free(icpy);
4291 }
4292 
prep_dbnomics_series(gretl_bundle * b,DATASET * dbset)4293 static int prep_dbnomics_series (gretl_bundle *b,
4294 				 DATASET *dbset)
4295 {
4296     gretl_array *A;
4297     gretl_matrix *v;
4298     const char *id;
4299     int T, err = 0;
4300 
4301     T = gretl_bundle_get_int(b, "T", &err);
4302     A = gretl_bundle_get_array(b, "period", &err);
4303     v = gretl_bundle_get_matrix(b, "value", &err);
4304     id = gretl_bundle_get_string(b, "series_code", &err);
4305 
4306     if (!err && (T <= 0 || A == NULL || v == NULL)) {
4307 	err = E_DATA;
4308     }
4309 
4310     if (!err) {
4311 	char **S = gretl_array_get_strings(A, &T);
4312 	gchar *fname;
4313 	FILE *fp;
4314 	int t;
4315 
4316 	fname = g_strdup_printf("%sdnomics_tmp.txt", gretl_dotdir());
4317 	fp = gretl_fopen(fname, "w");
4318 	if (fp == NULL) {
4319 	    err = E_FOPEN;
4320 	} else {
4321 	    gretl_push_c_numeric_locale();
4322 	    fputs("obs dbnomics_data\n", fp);
4323 	    for (t=0; t<T; t++) {
4324 		if (na(v->val[t])) {
4325 		    fprintf(fp, "%s NA\n", S[t]);
4326 		} else {
4327 		    fprintf(fp, "%s %.12g\n", S[t], v->val[t]);
4328 		}
4329 	    }
4330 	    gretl_pop_c_numeric_locale();
4331 	    fclose(fp);
4332 	    err = import_csv(fname, dbset, OPT_NONE, NULL);
4333 	    if (!err && id != NULL) {
4334 		series_set_display_name(dbset, 1, id);
4335 	    }
4336 	    gretl_remove(fname);
4337 	}
4338 	g_free(fname);
4339     }
4340 
4341     return err;
4342 }
4343 
add_dbnomics_data(windata_t * vwin)4344 int add_dbnomics_data (windata_t *vwin)
4345 {
4346     gretl_bundle *b = vwin->data;
4347     DATASET *dbset = NULL;
4348     int err;
4349 
4350     dbset = datainfo_new();
4351     if (dbset == NULL) {
4352 	nomem();
4353 	return E_ALLOC;
4354     } else {
4355 	int freeit = 1;
4356 
4357 	err = prep_dbnomics_series(b, dbset);
4358 	if (!err) {
4359 	    char vname[VNAMELEN];
4360 	    const char *S[4];
4361 	    gchar *full_id = NULL;
4362 	    gchar *descrip = NULL;
4363 	    int cancel = 0;
4364 
4365 	    /* construct a default name for the series */
4366 	    *vname = '\0';
4367 	    S[0] = gretl_bundle_get_string(b, "series_code", &err);
4368 	    if (!err) {
4369 		gretl_normalize_varname(vname, S[0], 0, 0);
4370 	    }
4371 	    /* construct its description */
4372 	    S[1] = gretl_bundle_get_string(b, "provider_code", &err);
4373 	    S[2] = gretl_bundle_get_string(b, "dataset_code", &err);
4374 	    S[3] = gretl_bundle_get_string(b, "series_name", &err);
4375 	    if (!err) {
4376 		full_id = g_strdup_printf("%s/%s/%s", S[1], S[2], S[0]);
4377 		descrip = g_strdup_printf("%s: %s", full_id, S[3]);
4378 	    }
4379 	    name_new_series_dialog(vname, &descrip, vwin, &cancel);
4380 	    if (!cancel) {
4381 		set_dbnomics_id(full_id);
4382 		strcpy(dbset->varname[1], vname);
4383 		series_set_label(dbset, 1, descrip);
4384 		series_set_display_name(dbset, 1, "");
4385 		add_dbdata(vwin, dbset, NULL, &freeit);
4386 		unset_dbnomics_id();
4387 	    }
4388 	    g_free(descrip);
4389 	    g_free(full_id);
4390 	}
4391 	if (freeit) {
4392 	    destroy_dataset(dbset);
4393 	}
4394     }
4395 
4396     return err;
4397 }
4398 
show_dbnomics_data(windata_t * vwin,int plot)4399 int show_dbnomics_data (windata_t *vwin, int plot)
4400 {
4401     gretl_bundle *b = vwin->data;
4402     DATASET dbset = {0};
4403     int err;
4404 
4405     err = prep_dbnomics_series(b, &dbset);
4406     if (!err) {
4407 	if (plot) {
4408 	    graph_dbdata(&dbset);
4409 	} else {
4410 	    display_dbdata(&dbset);
4411 	}
4412     }
4413 
4414     free_Z(&dbset);
4415     clear_datainfo(&dbset, CLEAR_FULL);
4416 
4417     return err;
4418 }
4419 
populate_dbfilelist(windata_t * vwin,int * pndb)4420 gint populate_dbfilelist (windata_t *vwin, int *pndb)
4421 {
4422     GtkListStore *store;
4423     GtkTreeIter iter;
4424     char **dirnames;
4425     GDir *dir;
4426     int i, n_dirs;
4427     int nf, ndb = 0;
4428     int err = 0;
4429 
4430 #if DB_SEARCH_DEBUG
4431     fprintf(stderr, "populate_dbfilelist...\n");
4432 #endif
4433 
4434     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox)));
4435     gtk_list_store_clear(store);
4436     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
4437 
4438     dirnames = get_plausible_search_dirs(DB_SEARCH, &n_dirs);
4439 
4440     for (i=0; i<n_dirs; i++) {
4441 	dir = gretl_opendir(dirnames[i]);
4442 	if (dir != NULL) {
4443 	    nf = read_db_files_in_dir(dir, vwin->role, dirnames[i], store, &iter);
4444 #if DB_SEARCH_DEBUG
4445 	    fprintf(stderr, " found %d db files in '%s'\n", nf, dirnames[i]);
4446 #endif
4447 	    ndb += nf;
4448 	    g_dir_close(dir);
4449 	}
4450     }
4451 
4452     strings_array_free(dirnames, n_dirs);
4453 
4454     if (ndb == 0) {
4455 	errbox(_("No database files found"));
4456 	err = 1;
4457     } else {
4458 	maybe_prune_db_list(GTK_TREE_VIEW(vwin->listbox), &ndb);
4459 	presort_treelist(vwin);
4460     }
4461 
4462     if (pndb != NULL) {
4463 	*pndb = ndb;
4464     }
4465 
4466     return err;
4467 }
4468 
set_db_dir_callback(windata_t * vwin,char * path)4469 void set_db_dir_callback (windata_t *vwin, char *path)
4470 {
4471     GDir *dir = gretl_opendir(path);
4472     int ndb = 0;
4473 
4474     if (dir != NULL) {
4475 	GtkListStore *store;
4476 	GtkTreeIter iter;
4477 
4478 	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vwin->listbox)));
4479 	gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
4480 	ndb = read_db_files_in_dir(dir, vwin->role, path, store, &iter);
4481 	g_dir_close(dir);
4482     }
4483 
4484     if (ndb == 0) {
4485 	warnbox(_("No database files found"));
4486     }
4487 }
4488 
set_compact_info_from_default(int method)4489 static void set_compact_info_from_default (int method)
4490 {
4491     int i;
4492 
4493     for (i=1; i<dataset->v; i++) {
4494 	if (series_get_compact_method(dataset, i) == COMPACT_NONE) {
4495 	    series_set_compact_method(dataset, i, method);
4496 	}
4497     }
4498 }
4499 
do_compact_data_set(void)4500 void do_compact_data_set (void)
4501 {
4502     CompactMethod method = COMPACT_AVG;
4503     int err, newpd = 0, monstart = 1;
4504     int repday = 0;
4505     int *pmonstart = NULL;
4506 
4507     if (maybe_restore_full_data(COMPACT)) {
4508 	return;
4509     }
4510 
4511     if (dated_seven_day_data(dataset)) {
4512 	pmonstart = &monstart;
4513     }
4514 
4515     data_compact_dialog(dataset->pd, &newpd, pmonstart,
4516 			&method, &repday, mdata->main);
4517 
4518     if (method == COMPACT_NONE) {
4519 	/* the user cancelled */
4520 	fprintf(stderr, "canceled!\n");
4521 	return;
4522     }
4523 
4524     err = compact_data_set(dataset, newpd, method, monstart, repday);
4525 
4526     if (err) {
4527 	gui_errmsg(err);
4528     } else {
4529 	const char *mstr = compact_method_string(method);
4530 
4531 	if (mstr != NULL) {
4532 	    lib_command_sprintf("dataset compact %d %s", newpd, mstr);
4533 	} else {
4534 	    lib_command_sprintf("dataset compact %d", newpd);
4535 	}
4536 	record_command_verbatim();
4537 
4538 	mark_dataset_as_modified();
4539 	if (method == COMPACT_SPREAD) {
4540 	    populate_varlist();
4541 	}
4542 	set_compact_info_from_default(method);
4543     }
4544 }
4545 
do_expand_data_set(void)4546 void do_expand_data_set (void)
4547 {
4548     int newpd = -1;
4549     int err = 0;
4550 
4551     if (dataset->pd != 1 && dataset->pd != 4) {
4552 	/* should not happen! */
4553 	return;
4554     }
4555 
4556     if (maybe_restore_full_data(EXPAND)) {
4557 	return;
4558     }
4559 
4560     /* supported: annual to quarterly, quarterly to monthly,
4561        or annual to monthly */
4562     newpd = (dataset->pd == 1)? 4 : 12;
4563     data_expand_dialog(&newpd, mdata->main);
4564 
4565     if (newpd < 0) {
4566 	/* canceled */
4567 	return;
4568     }
4569 
4570     gretl_error_clear();
4571     err = expand_data_set(dataset, newpd);
4572 
4573     if (err) {
4574 	gui_errmsg(err);
4575     } else {
4576 	mark_dataset_as_modified();
4577     }
4578 }
4579