1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "libgretl.h"
21 #include "libset.h"
22 #include "gretl_func.h"
23 #include "gretl_string_table.h"
24 #include "texprint.h"
25 #include "addons_utils.h"
26 
27 #if defined(USE_RLIB) || defined(HAVE_MPI)
28 # include "gretl_foreign.h"
29 #endif
30 
31 #ifdef USE_CURL
32 # include "gretl_www.h"
33 #endif
34 
35 #include <unistd.h>
36 
37 #ifdef WIN32
38 # include "gretl_win32.h"
39 #endif
40 
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include <fcntl.h> /* for 'open' */
46 
47 #include <glib/gstdio.h>
48 
49 #if defined(WIN32) && defined(PKGBUILD)
50 # define PLUGIN_SFX "plugins"
51 #elif defined(USE_GTK3)
52 # define PLUGIN_SFX "gretl-gtk3"
53 #else
54 # define PLUGIN_SFX "gretl-gtk2"
55 #endif
56 
57 struct INTERNAL_PATHS {
58     char gretldir[MAXLEN];
59     char dotdir[MAXLEN];
60     char workdir[MAXLEN];
61     char gnuplot[MAXLEN];
62     char plotfile[MAXLEN];
63     char plugpath[MAXLEN];
64     char binbase[MAXLEN+4];
65     char x12a[MAXLEN];
66     char x12adir[MAXLEN];
67     char tramo[MAXLEN];
68     char tramodir[MAXLEN];
69     char rbinpath[MAXLEN];
70     char rlibpath[MAXLEN];
71     char oxlpath[MAXLEN];
72     char octpath[MAXLEN];
73     char statapath[MAXLEN];
74     char pypath[MAXLEN];
75     char jlpath[MAXLEN];
76     char lppath[MAXLEN];
77     char mpiexec[MAXLEN];
78     char mpi_hosts[MAXLEN];
79     char pngfont[128];
80     unsigned char status;
81 };
82 
83 static struct INTERNAL_PATHS paths;
84 
85 /* recorder for directories from which scripts were loaded */
86 static GList *script_dirs;
87 
88 static int force_en_cmdref;
89 static int force_en_fnref;
90 
set_helpfile_option(gretlopt opt)91 static void set_helpfile_option (gretlopt opt)
92 {
93     if (opt & OPT_N) {
94         force_en_cmdref = 1;
95         force_en_fnref = 1;
96     }
97 }
98 
99 static const char *helpfiles[] = {
100     /* TRANSLATORS: you may change the two-letter language code
101        if gretl_commands_en.xml has been translated for your language,
102        as in gretl_cli_cmdref.pt -- otherwise leave it untranslated
103     */
104     N_("gretl_cli_cmdref.en"),
105     /* TRANSLATORS: you may change the two-letter language code
106        if gretl_commands_en.xml has been translated for your language,
107        as in gretl_gui_cmdref.pt -- otherwise leave it untranslated
108     */
109     N_("gretl_gui_cmdref.en"),
110     /* TRANSLATORS: you may change the two-letter language code
111        if gretl_commands_en.xml has been translated for your language,
112        as in gretl_gui_help.pt -- otherwise leave it untranslated
113     */
114     N_("gretl_gui_help.en"),
115     /* TRANSLATORS: you may change the two-letter language code
116        if gretl_functions_en.xml has been translated for your language,
117        as in gretl_cli_fnref.pt -- otherwise leave it untranslated
118     */
119     N_("gretl_cli_fnref.en"),
120     /* TRANSLATORS: you may change the two-letter language code
121        if gretl_functions_en.xml has been translated for your language,
122        as in gretl_gui_fnref.pt -- otherwise leave it untranslated
123     */
124     N_("gretl_gui_fnref.en")
125 };
126 
helpfile_path(int id,int cli,int en)127 const char *helpfile_path (int id, int cli, int en)
128 {
129     static char hpath[MAXLEN+19];
130     int i = -1;
131 
132     *hpath = '\0';
133 
134     if ((id == GRETL_CMDREF && force_en_cmdref) ||
135         (id == GRETL_FUNCREF && force_en_fnref)) {
136         en = 1;
137     }
138 
139     if (cli) {
140         /* Command-line program */
141         if (id == GRETL_CMDREF) {
142             i = 0;
143         } else if (id == GRETL_FUNCREF) {
144             i = 3;
145         }
146     } else {
147         /* GUI program */
148         if (id == GRETL_CMDREF) {
149             i = 1;
150         } else if (id == GRETL_GUI_HELP) {
151             i = 2;
152         } else if (id == GRETL_FUNCREF) {
153             i = 4;
154         }
155     }
156 
157     if (i >= 0) {
158 	if (en || (strlen(_(helpfiles[i])) != strlen(helpfiles[i]))) {
159 	    sprintf(hpath, "%s%s", paths.gretldir, helpfiles[i]);
160 	} else {
161 	    sprintf(hpath, "%s%s", paths.gretldir, _(helpfiles[i]));
162 	}
163     }
164 
165     return hpath;
166 }
167 
using_translated_helpfile(int id)168 int using_translated_helpfile (int id)
169 {
170     int ret = 0;
171     int i = 0;
172 
173     if (id == GRETL_CMDREF) {
174         if (force_en_cmdref) return 0;
175         i = 1;
176     } else if (id == GRETL_FUNCREF) {
177         if (force_en_fnref) return 0;
178         i = 4;
179     } else {
180         return 0;
181     }
182 
183     /* If we're not forcing English help, the criterion is
184        that the relevant help file has a "translated" filename
185        and the translation can actually be opened.
186     */
187 
188     if (strcmp(helpfiles[i], _(helpfiles[i]))) {
189         gchar *test;
190         int err;
191 
192         test = g_strdup_printf("%s%s", paths.gretldir, _(helpfiles[i]));
193         err = gretl_test_fopen(test, "r");
194         if (err) {
195             if (id == GRETL_CMDREF) {
196                 force_en_cmdref = 1;
197             } else {
198                 force_en_fnref = 1;
199             }
200         } else {
201             ret = 1;
202         }
203 	g_free(test);
204     }
205 
206     return ret;
207 }
208 
209 /* If @fname does not already have suffix @sfx, add it.
210    With the qualification that if the @fname bears either of
211    the standard gretl data-file suffixes, ".gdt" or ".gdtb",
212    we won't stick the other one onto the end.
213 */
214 
maybe_add_suffix(char * fname,const char * sfx)215 static int maybe_add_suffix (char *fname, const char *sfx)
216 {
217     if (has_suffix(fname, ".gdtb") && !strcmp(sfx, ".gdt")) {
218         return 0;
219     } else if (has_suffix(fname, ".gdt") && !strcmp(sfx, ".gdtb")) {
220         return 0;
221     } else if (!has_suffix(fname, sfx)) {
222         strcat(fname, sfx);
223         return 1;
224     }
225 
226     return 0;
227 }
228 
229 /* Convenience wrapper macro for the GLib UTF-8 validation
230    function. If and only if this returns non-zero for a
231    given filename can that name be passed to GLib's gstdio
232    functions on MS Windows.
233 */
234 
235 #define valid_utf8(s) g_utf8_validate(s, -1, NULL)
236 
237 /**
238  * utf8_encoded:
239  * @s: the string to examine.
240  *
241  * The primary use of this function is to determine
242  * whether a filename can be passed to regular C-library
243  * functions on MS Windows: if it's in UTF-8 the answer
244  * is No -- unless it's in the ASCII subset of UTF-8.
245  *
246  * Returns: non-zero if @s validates as UTF-8 and
247  * contains bytes that are not printable ASCII,
248  * otherwise zero.
249  */
250 
utf8_encoded(const char * s)251 int utf8_encoded (const char *s)
252 {
253     int ret = 0;
254 
255     if (g_utf8_validate(s, -1, NULL)) {
256         const unsigned char *p = (const unsigned char *) s;
257 
258         while (*p) {
259             if (*p < 32 || *p > 126) {
260                 /* not printable ASCII */
261                 ret = 1;
262                 break;
263             }
264             p++;
265         }
266     }
267 
268     return ret;
269 }
270 
271 #define FDEBUG 0
272 
273 /**
274  * gretl_fopen:
275  * @fname: name of file to be opened.
276  * @mode: mode in which to open the file.
277  *
278  * A wrapper for the C library's fopen(), using
279  * g_fopen() on Windows, and adding some error handling.
280  *
281  * Returns: file pointer, or %NULL on failure.
282  */
283 
gretl_fopen(const char * fname,const char * mode)284 FILE *gretl_fopen (const char *fname, const char *mode)
285 {
286     FILE *fp = NULL;
287 
288     gretl_error_clear();
289 
290 #ifdef WIN32
291     fp = g_fopen(fname, mode);
292 #else
293     fp = fopen(fname, mode);
294 #endif
295 
296     if (errno != 0) {
297         gretl_errmsg_set_from_errno(fname, errno);
298     }
299 
300     return fp;
301 }
302 
303 /**
304  * gretl_mktemp:
305  * @pattern: template for filename; must end with "XXXXXX".
306  * @mode: e.g. "w" for text use or "wb" for binary mode.
307  *
308  * A wrapper for the combination of mkstemp() and fdopen(),
309  * using the associated GLib functions on Windows.
310  * On successful exit @pattern holds the name of the newly
311  * created file.
312  *
313  * Returns: file pointer, or %NULL on failure.
314  */
315 
gretl_mktemp(char * pattern,const char * mode)316 FILE *gretl_mktemp (char *pattern, const char *mode)
317 {
318     FILE *fp = NULL;
319     int fd;
320 
321     gretl_error_clear();
322 
323 #ifdef WIN32
324     fd = g_mkstemp(pattern);
325 #else
326     fd = mkstemp(pattern);
327 #endif
328 
329     if (errno != 0) {
330         gretl_errmsg_set_from_errno(NULL, errno);
331     } else if (fd != -1) {
332         fp = fdopen(fd, mode);
333     }
334 
335     return fp;
336 }
337 
338 /**
339  * gretl_test_fopen:
340  * @fname: name of file to be opened.
341  * @mode: mode as used with fopen().
342  *
343  * Attempts to open @fname in the given mode; if the opening
344  * is successful the stream is then closed.
345  *
346  * Returns: 0 on success, -1 on filename encoding
347  * failure, or the system errno on failure of fopen().
348  */
349 
gretl_test_fopen(const char * fname,const char * mode)350 int gretl_test_fopen (const char *fname, const char *mode)
351 {
352     FILE *fp = NULL;
353     int err = 0;
354 
355     gretl_error_clear();
356 
357 #ifdef WIN32
358     fp = g_fopen(fname, mode);
359 #else
360     fp = fopen(fname, mode);
361 #endif
362 
363     if (fp == NULL) {
364         err = errno;
365     } else {
366         fclose(fp);
367         if (*mode == 'w') {
368             remove(fname);
369         }
370     }
371 
372     return err;
373 }
374 
375 /**
376  * gretl_open:
377  * @pathname: name of file to be opened.
378  * @flags: flags to pass to the system open().
379  * @mode: ignored unless @flags contains O_CREAT
380  * or O_TMPFILE.
381  *
382  * A wrapper for the C library's open(), using GLib on
383  * Windows and adding some error handling.
384  *
385  * Returns: new file descriptor, or -1 on error.
386  */
387 
gretl_open(const char * pathname,int flags,int mode)388 int gretl_open (const char *pathname, int flags, int mode)
389 {
390     mode_t m = 0;
391     int fd = -1;
392 
393     gretl_error_clear();
394 
395     if (flags & O_CREAT) {
396         m = (mode_t) mode;
397     }
398 
399 #ifdef WIN32
400     fd = g_open(pathname, flags, m);
401 #else
402     fd = open(pathname, flags, m);
403 #endif
404 
405     if (errno != 0) {
406         gretl_errmsg_set_from_errno(pathname, errno);
407     }
408 
409     return fd;
410 }
411 
412 /**
413  * gretl_stat:
414  * @fname: name of file to be examined.
415  * @buf: pointer to a C struct stat (or NULL is OK if
416  * the caller just wants the return value from the stat
417  * call).
418  *
419  * A wrapper for the C library's stat(), making allowance for
420  * the possibility that @fname has to be converted from UTF-8
421  * to the locale encoding or vice versa.
422  *
423  * Returns: 0 on success, non-zero on failure.
424  */
425 
gretl_stat(const char * fname,struct stat * buf)426 int gretl_stat (const char *fname, struct stat *buf)
427 {
428     struct stat tmp = {0};
429 
430     gretl_error_clear();
431 
432 #ifdef WIN32
433     if (utf8_encoded(fname)) {
434         /* A native stat() call won't work with such a filename:
435            we should either call g_stat(), which expects UTF-8
436            on Windows, or convert @fname before calling stat().
437            Unfortunately g_stat() from GLib 2.36.4 crashes on
438            (some variants of) 32-bit Windows, so it seems we need
439            to do the conversion ourselves.
440         */
441         gunichar2 *wname;
442 
443         wname = g_utf8_to_utf16(fname, -1, NULL, NULL, NULL);
444         if (wname != NULL) {
445             int ret = wstat(wname, buf == NULL ? &tmp : buf);
446 
447             g_free(wname);
448             return ret;
449         }
450     }
451 #endif
452 
453     return stat(fname, buf == NULL ? &tmp : buf);
454 }
455 
456 /**
457  * gretl_file_exists:
458  * @fname: name of file to be examined.
459  *
460  * Uses the C library's stat() function, making allowance for
461  * the possibility that @fname has to be converted from UTF-8
462  * to the locale encoding or vice versa.
463  *
464  * Returns: 1 if @fname is the name of an existing file,
465  * otherwise 0.
466  */
467 
gretl_file_exists(const char * fname)468 int gretl_file_exists (const char *fname)
469 {
470     return gretl_stat(fname, NULL) == 0;
471 }
472 
473 #ifdef WIN32
474 
475 /* Note: renaming doesn't work on Windows if the target
476    already exists. If we end up trying to rename in this
477    case it presumably means that @newpath represents
478    stale data, and should be removed first.
479 */
480 
win32_rename(const char * oldpath,const char * newpath)481 static int win32_rename (const char *oldpath,
482                          const char *newpath)
483 {
484     if (gretl_file_exists(newpath)) {
485         /* get rid of stale target */
486         gretl_deltree(newpath);
487     }
488 
489     return g_rename(oldpath, newpath);
490 }
491 
492 #endif
493 
494 /**
495  * gretl_rename:
496  * @oldpath: name of file to be opened.
497  * @newpath: new name to give the file.
498  *
499  * A wrapper for the C library's rename(), making allowance for
500  * the possibility that @oldpath and/or @newpath have to be
501  * converted from UTF-8 to the locale encoding or vice versa.
502  *
503  * Returns: 0 on success, non-zero on failure.
504  */
505 
gretl_rename(const char * oldpath,const char * newpath)506 int gretl_rename (const char *oldpath, const char *newpath)
507 {
508     int err = 0;
509 
510     if (!strcmp(oldpath, newpath)) {
511         /* check for no-op */
512         return 0;
513     }
514 
515     gretl_error_clear();
516 
517 #ifdef WIN32
518     err = win32_rename(oldpath, newpath);
519 #else
520     err = rename(oldpath, newpath);
521 #endif
522 
523     if (errno != 0) {
524         perror("rename");
525         gretl_errmsg_set_from_errno("gretl_rename", errno);
526     }
527 
528     return err;
529 }
530 
531 /**
532  * gretl_remove:
533  * @path: name of file or directory to remove.
534  *
535  * A wrapper for remove(), using the GLib counterpart
536  * on Windows.
537  *
538  * Returns: 0 on sucess, non-zero on failure.
539  */
540 
gretl_remove(const char * path)541 int gretl_remove (const char *path)
542 {
543 #ifdef WIN32
544     return g_remove(path);
545 #else
546     return remove(path);
547 #endif
548 }
549 
550 /**
551  * gretl_gzopen:
552  * @fname: name of gzipped file to be opened.
553  * @mode: mode in which to open the file.
554  *
555  * A wrapper for zlib's gzopen(), making allowance for
556  * the possibility that @fname has to be converted from
557  * UTF-8 to UTF-16.
558  *
559  * Returns: pointer to gzip stream, or %NULL on failure.
560  */
561 
gretl_gzopen(const char * fname,const char * mode)562 gzFile gretl_gzopen (const char *fname, const char *mode)
563 {
564     gzFile fz = NULL;
565 
566     gretl_error_clear();
567 
568 #ifdef WIN32
569     if (utf8_encoded(fname)) {
570         /* here we have to convert to UTF-16 */
571         gunichar2 *tmp = g_utf8_to_utf16(fname, -1, NULL, NULL, NULL);
572 
573         if (tmp != NULL) {
574             fz = gzopen_w(tmp, mode);
575             g_free(tmp);
576         }
577     } else {
578         fz = gzopen(fname, mode); /* ? */
579     }
580 #else
581     fz = gzopen(fname, mode);
582 #endif
583 
584     if (errno != 0) {
585         gretl_errmsg_set_from_errno("gzopen", errno);
586     }
587 
588     return fz;
589 }
590 
591 /**
592  * gretl_chdir:
593  * @path: name of directory.
594  *
595  * A wrapper for POSIX chdir(), making allowance for
596  * the possibility that @path has to be converted from
597  * UTF-8 to UTF-16 on Windows.
598  *
599  * Returns: 0 on success, non-zero on failure.
600  */
601 
gretl_chdir(const char * path)602 int gretl_chdir (const char *path)
603 {
604     int err = 0;
605 
606     gretl_error_clear();
607 
608 #ifdef WIN32
609     err = g_chdir(path);
610 #else
611     err = chdir(path);
612 #endif
613 
614     if (errno != 0) {
615         gretl_errmsg_set_from_errno("chdir", errno);
616     }
617 
618     return err;
619 }
620 
621 /**
622  * gretl_isdir:
623  * @path: path to check.
624  *
625  * A test for whether or not @path is the name of a directory,
626  * allowing for the possibility that @path has to be converted
627  * from UTF-8 to UTF-16.
628  *
629  * Returns: 1 if @path is the name of a directory, else 0.
630  */
631 
gretl_isdir(const char * path)632 int gretl_isdir (const char *path)
633 {
634     return g_file_test(path, G_FILE_TEST_IS_DIR);
635 }
636 
637 /**
638  * gretl_mkdir:
639  * @path: name of directory to be created.
640  *
641  * Calls the underlying library function to create the
642  * specified directory with mode 0755.  If the directory in
643  * question already exists, this does not count as an error.
644  *
645  * Returns: 0 on success, non-zero on error.
646  */
647 
gretl_mkdir(const char * path)648 int gretl_mkdir (const char *path)
649 {
650     int err;
651 
652     errno = 0;
653     err = g_mkdir_with_parents(path, 0755);
654 
655     if (err) {
656         fprintf(stderr, "%s: %s\n", path, gretl_strerror(errno));
657         err = 1;
658     }
659 
660     return err;
661 }
662 
real_delete_recursive(const char * path)663 static int real_delete_recursive (const char *path)
664 {
665     GDir *dir;
666     int err = 0;
667 
668     errno = 0;
669     dir = g_dir_open(path, 0, NULL);
670 
671     if (dir == NULL) {
672         err = 1;
673     } else {
674         const gchar *fname;
675 
676         err = g_chdir(path);
677         while ((fname = g_dir_read_name(dir)) != NULL && !err) {
678             /* recursively delete dir's contents */
679             if (strcmp(fname, ".") && strcmp(fname, "..")) {
680                 if (g_file_test(fname, G_FILE_TEST_IS_DIR)) {
681                     err = real_delete_recursive(fname);
682                 } else {
683                     err = g_remove(fname);
684                 }
685             }
686         }
687         if (!err) {
688             g_dir_close(dir);
689             /* delete the directory itself */
690             if (g_chdir("..") == 0) {
691                 err = g_remove(path);
692             }
693         }
694     }
695 
696     if (err) {
697         gretl_errmsg_set_from_errno(path, errno);
698         err = E_FOPEN;
699     }
700 
701     return err;
702 }
703 
704 /**
705  * gretl_deltree:
706  * @path: name of directory to be deleted.
707  *
708  * Carries out recursive deletion of the specified directory.
709  *
710  * Returns: 0 on success, non-zero on error.
711  */
712 
gretl_deltree(const char * path)713 int gretl_deltree (const char *path)
714 {
715     gchar *savedir = NULL;
716     int err;
717 
718     savedir = g_get_current_dir();
719     err = real_delete_recursive(path);
720 
721     if (savedir != NULL) {
722         g_chdir(savedir);
723         g_free(savedir);
724     }
725 
726     return err;
727 }
728 
gretl_opendir(const char * name)729 GDir *gretl_opendir (const char *name)
730 {
731     GError *error = NULL;
732     GDir *dir;
733 
734     dir = g_dir_open(name, 0, &error);
735 
736     if (error != NULL) {
737         gretl_errmsg_set(error->message);
738         g_error_free(error);
739     }
740 
741     return dir;
742 }
743 
744 /**
745  * gretl_setenv:
746  * @name: name of variable to be set.
747  * @value: value to set.
748  *
749  * Cross-platform wrapper for setenv().
750  *
751  * Returns: 0 on success, non-zero on failure.
752  */
753 
gretl_setenv(const char * name,const char * value)754 int gretl_setenv (const char *name, const char *value)
755 {
756 #ifdef WIN32
757     gchar *estr;
758     int ok;
759 
760     /* belt and braces */
761     estr = g_strdup_printf("%s=%s", name, value);
762     putenv(estr);
763 
764     ok = SetEnvironmentVariable(name, value);
765 
766     return !ok;
767 #else
768     return setenv(name, value, 1);
769 #endif
770 }
771 
772 /**
773  * gretl_write_access:
774  * @fname: name of file to test.
775  *
776  * Returns: 0 on success (meaning that the current user has
777  * write access to @fname), non-zero on failure.
778  */
779 
gretl_write_access(char * fname)780 int gretl_write_access (char *fname)
781 {
782     int err;
783 
784     gretl_error_clear();
785 
786 #ifdef WIN32
787     err = win32_write_access(fname);
788 #else
789     err = access(fname, W_OK);
790     if (errno != 0) {
791         gretl_errmsg_set_from_errno(fname, errno);
792     }
793 #endif
794 
795     return err;
796 }
797 
798 /**
799  * gretl_is_xml_file:
800  * @fname: name of file to test.
801  *
802  * Returns: 1 if @fname appears to be a (possibly gzipped) XML file,
803  * otherwise 0.
804  */
805 
gretl_is_xml_file(const char * fname)806 int gretl_is_xml_file (const char *fname)
807 {
808     gzFile fz;
809     char test[6];
810     int ret = 0;
811 
812     fz = gretl_gzopen(fname, "rb");
813     if (fz != Z_NULL) {
814         if (gzread(fz, test, 5)) {
815             test[5] = '\0';
816             if (!strcmp(test, "<?xml")) ret = 1;
817         }
818         gzclose(fz);
819     }
820 
821     gretl_error_clear();
822 
823     return ret;
824 }
825 
826 /**
827  * gretl_path_prepend:
828  * @file: target filename.
829  * @path: path to prepend.
830  *
831  * Creates a path string by prepending @path, plus an appropriate
832  * separator if needed, to @file.  The result is written back into
833  * @file: this variable is assumed to have storage for at least
834  * #MAXLEN characters.
835  *
836  * Returns: 0 on success, or 1 if the final path string would
837  * exceed #MAXLEN characters (including nul-termination).
838  */
839 
gretl_path_prepend(char * file,const char * path)840 int gretl_path_prepend (char *file, const char *path)
841 {
842     int n = strlen(file) + strlen(path) + 1;
843     char temp[MAXLEN];
844 
845     if (n > MAXLEN) {
846         return 1;
847     }
848 
849     strcpy(temp, path);
850     n = strlen(temp);
851 
852     if (temp[n-1] != SLASH && n < MAXLEN - 1) {
853         strcat(temp, SLASHSTR);
854     }
855 
856     strcat(temp, file);
857     strcpy(file, temp);
858 
859     return 0;
860 }
861 
862 enum {
863     ADD_GDT = 1 << 0,
864     ADD_GFN = 1 << 1,
865     SUBDIRS = 1 << 2
866 };
867 
try_open_file(char * targ,const char * finddir,const gchar * dname,int flags)868 static int try_open_file (char *targ, const char *finddir,
869                           const gchar *dname, int flags)
870 {
871     char tmp[MAXLEN];
872     int err, found = 0;
873 
874     strcpy(tmp, finddir);
875     strcat(tmp, dname);
876     strcat(tmp, SLASHSTR);
877     strcat(tmp, targ);
878 
879     err = gretl_test_fopen(tmp, "r");
880 
881     if (err && (flags & ADD_GDT)) {
882         if (maybe_add_suffix(tmp, ".gdt")) {
883             err = gretl_test_fopen(tmp, "r");
884             if (err) {
885                 /* try .gdtb also */
886                 strcat(tmp, "b");
887                 err = gretl_test_fopen(tmp, "r");
888             }
889         }
890     }
891 
892     if (!err) {
893         strcpy(targ, tmp);
894         found = 1;
895     }
896 
897     return found;
898 }
899 
make_finddir(char * targ,const char * src)900 static void make_finddir (char *targ, const char *src)
901 {
902     int n = strlen(src);
903 
904     strcpy(targ, src);
905 
906     if (targ[n-1] != SLASH) {
907         strcat(targ, SLASHSTR);
908     }
909 }
910 
got_subdir(const char * topdir,const gchar * dname)911 static int got_subdir (const char *topdir, const gchar *dname)
912 {
913     int ret = 0;
914 
915     if (strcmp(dname, ".") && strcmp(dname, "..")) {
916         char tmp[MAXLEN];
917         GDir *sub;
918 
919         strcpy(tmp, topdir);
920         strcat(tmp, dname);
921         sub = gretl_opendir(tmp);
922         if (sub != NULL) {
923             g_dir_close(sub);
924             ret = 1;
925         }
926     }
927 
928     return ret;
929 }
930 
931 /* Try to find @fname in a first-level subdirectory of @topdir.
932    Return 1 if found, otherwise 0.
933 */
934 
find_in_subdir(const char * topdir,char * fname,int flags)935 static int find_in_subdir (const char *topdir, char *fname, int flags)
936 {
937     GDir *dir;
938     const gchar *dname;
939     char finddir[MAXLEN];
940     int found = 0;
941 
942     /* make find target */
943     make_finddir(finddir, topdir);
944 
945     dir = gretl_opendir(finddir);
946     if (dir != NULL) {
947         while (!found && (dname = g_dir_read_name(dir))) {
948             if (got_subdir(finddir, dname)) {
949                 found = try_open_file(fname, finddir, dname, flags);
950             }
951         }
952         g_dir_close(dir);
953     }
954 
955     return found;
956 }
957 
search_dir(char * fname,const char * topdir,int flags)958 static char *search_dir (char *fname, const char *topdir, int flags)
959 {
960     char orig[MAXLEN];
961     int err;
962 
963     strcpy(orig, fname);
964 
965     if (gretl_path_prepend(fname, topdir) == 0) {
966         err = gretl_test_fopen(fname, "r");
967         if (!err) {
968             return fname;
969         }
970         if (flags & ADD_GDT) {
971             if (maybe_add_suffix(fname, ".gdt")) {
972                 err = gretl_test_fopen(fname, "r");
973                 if (!err) {
974                     return fname;
975                 }
976             } else if (maybe_add_suffix(fname, ".gdtb")) {
977                 err = gretl_test_fopen(fname, "r");
978                 if (!err) {
979                     return fname;
980                 }
981             }
982         } else if (flags & ADD_GFN) {
983             if (maybe_add_suffix(fname, ".gfn")) {
984                 err = gretl_test_fopen(fname, "r");
985                 if (!err) {
986                     return fname;
987                 }
988             }
989         }
990         strcpy(fname, orig);
991         if (flags & SUBDIRS) {
992             if (find_in_subdir(topdir, fname, flags)) {
993                 return fname;
994             }
995         }
996     }
997 
998     return NULL;
999 }
1000 
1001 /**
1002  * get_plausible_search_dirs:
1003  * @stype: DATA_SEARCH for data file packages, DB_SEARCH for
1004  * gretl databases, FUNCS_SEARCH for function packages, or
1005  * SCRIPT_SEARCH for hansl scripts.
1006  * @n_dirs: location to receive the number of directories.
1007  *
1008  * Returns: an array of plausible search paths, depending on the
1009  * @type of search. The array should be freed when you are done
1010  * with it, using strings_array_free().
1011  */
1012 
get_plausible_search_dirs(SearchType stype,int * n_dirs)1013 char **get_plausible_search_dirs (SearchType stype, int *n_dirs)
1014 {
1015     char **dirs = NULL;
1016     const char *subdir;
1017     char dirname[MAXLEN];
1018     int err = 0;
1019 
1020     *n_dirs = 0;
1021 
1022     if (stype == FUNCS_SEARCH) {
1023 	/* for testing of gfns */
1024 	char *forcepath = getenv("FORCE_GFN_PATH");
1025 
1026 	if (forcepath != NULL) {
1027 	    err = strings_array_add(&dirs, n_dirs, forcepath);
1028 	}
1029     }
1030 
1031     if (stype == DATA_SEARCH) {
1032         subdir = "data";
1033     } else if (stype == DB_SEARCH) {
1034         subdir = "db";
1035     } else if (stype == FUNCS_SEARCH) {
1036         subdir = "functions";
1037     } else if (stype == SCRIPT_SEARCH) {
1038         subdir = "scripts";
1039     } else {
1040         fprintf(stderr, "get_plausible_search_dir: no type specified\n");
1041         return NULL;
1042     }
1043 
1044     /* system dir first */
1045     gretl_build_path(dirname, gretl_home(), subdir, NULL);
1046     err = strings_array_add(&dirs, n_dirs, dirname);
1047 
1048 #ifdef OS_OSX
1049     if (!err) {
1050         /* the user's ~/Library */
1051         gretl_build_path(dirname, gretl_app_support_dir(), subdir, NULL);
1052         err = strings_array_add(&dirs, n_dirs, dirname);
1053     }
1054 #else
1055     if (!err) {
1056         /* the user's dotdir */
1057         gretl_build_path(dirname, gretl_dotdir(), subdir, NULL);
1058         err = strings_array_add(&dirs, n_dirs, dirname);
1059     }
1060 #endif
1061 
1062     if (stype == FUNCS_SEARCH) {
1063 	/* we don't really want the additional paths below? */
1064 	return dirs;
1065     }
1066 
1067     if (!err) {
1068         /* the user's working dir */
1069         gretl_build_path(dirname, gretl_workdir(), subdir, NULL);
1070         err = strings_array_add(&dirs, n_dirs, dirname);
1071     }
1072 
1073     if (!err) {
1074         /* working dir, no subdir */
1075         strcpy(dirname, gretl_workdir());
1076         err = strings_array_add(&dirs, n_dirs, dirname);
1077     }
1078 
1079     if (!err) {
1080         /* a legacy thing: some files may have been written to
1081            the "default workdir" in the past
1082         */
1083         const char *wd = maybe_get_default_workdir();
1084 
1085         if (wd != NULL) {
1086             gretl_build_path(dirname, wd, subdir, NULL);
1087             err = strings_array_add(&dirs, n_dirs, dirname);
1088             if (!err && stype != FUNCS_SEARCH) {
1089                 strcpy(dirname, wd);
1090                 err = strings_array_add(&dirs, n_dirs, dirname);
1091             }
1092         }
1093     }
1094 
1095     return dirs;
1096 }
1097 
1098 /* it's a dirent thing */
1099 #ifndef NAME_MAX
1100 # define NAME_MAX 255
1101 #endif
1102 
1103 /**
1104  * gretl_function_package_get_path:
1105  * @name: the name of the package to find, without the .gfn extension.
1106  * @type: %PKG_SUBDIR for a package that lives in its own subdirectory,
1107  * %PKG_TOPLEV for a package file not in a subdirectory, or %PKG_ALL
1108  * for a package that may be at either level.
1109  *
1110  * Searches a list of directories in which we might expect to find
1111  * function packages, and, if the package in question is found,
1112  * returns a newly allocated string holding the full path to
1113  * the package's gfn file. Public (system) directories are
1114  * searched first, then directories in the user's filespace.
1115  *
1116  * Returns: allocated path on success, otherwise NULL.
1117  */
1118 
gretl_function_package_get_path(const char * name,PkgType type)1119 char *gretl_function_package_get_path (const char *name,
1120                                        PkgType type)
1121 {
1122     char *ret = NULL;
1123     char path[FILENAME_MAX];
1124     char **dirs;
1125     int err, found = 0;
1126     int i, n_dirs;
1127 
1128     if (type == PKG_ALL || type == PKG_SUBDIR) {
1129         if (is_gretl_addon(name)) {
1130             return gretl_addon_get_path(name);
1131         }
1132     }
1133 
1134     *path = '\0';
1135     dirs = get_plausible_search_dirs(FUNCS_SEARCH, &n_dirs);
1136 
1137     for (i=0; i<n_dirs && !found; i++) {
1138         const char *fndir = dirs[i];
1139         const char *dname;
1140         char *p, test[NAME_MAX+1];
1141         GDir *dir;
1142 
1143         if ((dir = gretl_opendir(fndir)) == NULL) {
1144             continue;
1145         }
1146 
1147         if (type != PKG_TOPLEV) {
1148             /* look preferentially for .gfn files in their own
1149                subdirectories */
1150             while ((dname = g_dir_read_name(dir)) != NULL && !found) {
1151                 if (!strcmp(dname, name)) {
1152                     sprintf(path, "%s%c%s%c%s.gfn", fndir, SLASH,
1153                             dname, SLASH, dname);
1154                     err = gretl_test_fopen(path, "r");
1155                     if (!err) {
1156                         found = 1;
1157                     } else {
1158                         *path = '\0';
1159                     }
1160                 }
1161             }
1162         }
1163 
1164         if (!found && type != PKG_SUBDIR) {
1165             /* look for .gfn files in the top-level functions
1166                directory */
1167             g_dir_rewind(dir);
1168             while ((dname = g_dir_read_name(dir)) != NULL && !found) {
1169                 if (has_suffix(dname, ".gfn")) {
1170                     strcpy(test, dname);
1171                     p = strrchr(test, '.');
1172                     *p = '\0';
1173                     if (!strcmp(test, name)) {
1174                         sprintf(path, "%s%c%s", fndir, SLASH, dname);
1175                         found = 1;
1176                     }
1177                 }
1178             }
1179         }
1180 
1181         g_dir_close(dir);
1182     }
1183 
1184     strings_array_free(dirs, n_dirs);
1185 
1186     if (*path != '\0') {
1187         ret = gretl_strdup(path);
1188     }
1189 
1190     return ret;
1191 }
1192 
1193 /* Search for file with basename @fname in directory
1194    @dirname, or in any subdirectory of same up to
1195    depth @maxdepth. If the file is found, write its
1196    path into @fullname and return 1, otherwise
1197    return 0 (= not found).
1198 */
1199 
find_file_in_dir(const char * fname,const char * dirname,char * fullname,int maxdepth,int depth)1200 static int find_file_in_dir (const char *fname,
1201                              const char *dirname,
1202                              char *fullname,
1203                              int maxdepth,
1204                              int depth)
1205 {
1206     char tmp[FILENAME_MAX];
1207     const gchar *dname;
1208     struct stat sbuf;
1209     GDir *dir;
1210     int found = 0;
1211 
1212     dir = gretl_opendir(dirname);
1213 
1214     if (dir == NULL) {
1215         return 0;
1216     }
1217 
1218     /* look for top-level plain file first */
1219     while (!found && (dname = g_dir_read_name(dir))) {
1220         if (!strcmp(dname, ".") ||
1221             !strcmp(dname, "..")) {
1222             continue;
1223         }
1224         sprintf(tmp, "%s%c%s", dirname, SLASH, dname);
1225         if (gretl_stat(tmp, &sbuf) < 0) {
1226             continue;
1227         } else if ((sbuf.st_mode & S_IFREG) &&
1228                    !strcmp(dname, fname)) {
1229             strcpy(fullname, tmp);
1230             found = 1;
1231         }
1232     }
1233 
1234     if (!found && depth < maxdepth) {
1235         /* then look in subdirs */
1236         g_dir_rewind(dir);
1237         depth++;
1238         while (!found && (dname = g_dir_read_name(dir))) {
1239             if (!strcmp(dname, ".") ||
1240                 !strcmp(dname, "..")) {
1241                 continue;
1242             }
1243             sprintf(tmp, "%s%c%s", dirname, SLASH, dname);
1244             if (gretl_stat(tmp, &sbuf) < 0) {
1245                 continue;
1246             } else if (sbuf.st_mode & S_IFDIR) {
1247                 found = find_file_in_dir(fname, tmp, fullname,
1248                                          maxdepth, depth);
1249             }
1250         }
1251     }
1252 
1253     g_dir_close(dir);
1254 
1255     return found;
1256 }
1257 
1258 /**
1259  * get_package_data_path:
1260  * @fname: the basename of the file whose full path is wanted.
1261  * @fullname: location to which the full path should be written
1262  * (should be at least FILENAME_MAX bytes).
1263  *
1264  * Looks for @fname in association with the name of a function
1265  * package, which must have been set previously using the
1266  * --frompkg option with the "open" command.
1267  *
1268  * Returns: 0 on success, non-zero code on error.
1269  */
1270 
get_package_data_path(const char * fname,char * fullname)1271 int get_package_data_path (const char *fname, char *fullname)
1272 {
1273     const char *pkgname;
1274     int err = 0;
1275 
1276     *fullname = '\0';
1277     pkgname = get_optval_string(OPEN, OPT_K);
1278 
1279     if (pkgname == NULL) {
1280         err = E_DATA;
1281     } else {
1282         const char *ppath;
1283         char *gfnpath;
1284 
1285         ppath = get_function_package_path_by_name(pkgname);
1286 
1287         if (ppath != NULL) {
1288             gfnpath = gretl_strdup(ppath);
1289         } else {
1290             gfnpath = gretl_addon_get_path(pkgname);
1291         }
1292 
1293         if (gfnpath == NULL) {
1294             gretl_errmsg_sprintf(_("Couldn't find package %s"),
1295                                  pkgname);
1296             err = E_DATA;
1297         } else {
1298             char *p = strrslash(gfnpath);
1299             const char *needle;
1300 
1301             if (p != NULL) {
1302                 *p = '\0';
1303             }
1304 
1305             /* trim path from @fname if present */
1306             needle = strrslash(fname);
1307             if (needle != NULL) {
1308                 needle++;
1309             } else {
1310                 needle = fname;
1311             }
1312 
1313             if (!find_file_in_dir(needle, gfnpath, fullname, 1, 0)) {
1314                 gretl_errmsg_sprintf(_("Couldn't find file %s for package %s"),
1315                                      needle, pkgname);
1316                 *fullname = '\0';
1317                 err = E_FOPEN;
1318             }
1319             free(gfnpath);
1320         }
1321     }
1322 
1323     return err;
1324 }
1325 
1326 #define SCRIPT_DIRS_DEBUG 0
1327 
1328 #if SCRIPT_DIRS_DEBUG
1329 
print_script_dirs(void)1330 static void print_script_dirs (void)
1331 {
1332     GList *L = g_list_first(script_dirs);
1333 
1334     if (L != NULL) {
1335         int i = 0;
1336 
1337         while (L != NULL) {
1338             fprintf(stderr, "script_dir %d: '%s'\n", ++i, (char *) L->data);
1339             L = L->next;
1340         }
1341         fputc('\n', stderr);
1342     }
1343 }
1344 
1345 #endif
1346 
1347 /**
1348  * gretl_addpath:
1349  * @fname: on input, the initially given file name; on output
1350  * a path may be prepended and/or a suffix may be appended.
1351  * This variable must be of size at least #MAXLEN bytes to allow
1352  * for possible additions.
1353  * @script: if non-zero, assume the file we're looking for
1354  * is a hansl script.
1355  *
1356  * Elementary path-searching: try adding various paths to the given
1357  * @fname and see if it can be opened. Usually called by get_full_filename().
1358  * If @fname does not already have a dot-extension we may also try adding
1359  * an appropriate gretl extension in case no file is found.
1360  *
1361  * Returns: the path to the file that was found (in @fname), or
1362  * NULL if no file could be found even allowing for prepending
1363  * a path and/or adding a suffix.
1364  */
1365 
gretl_addpath(char * fname,int script)1366 char *gretl_addpath (char *fname, int script)
1367 {
1368     char orig[MAXLEN];
1369     char *test;
1370     int found = 0;
1371     int err;
1372 
1373     /* keep a backup of the original input */
1374     strcpy(orig, fname);
1375 
1376     if (g_path_is_absolute(fname)) {
1377         err = gretl_test_fopen(fname, "r");
1378         if (err && !script && maybe_add_suffix(fname, ".gdt")) {
1379             err = gretl_test_fopen(fname, "r");
1380             if (err) {
1381                 strcpy(fname, orig);
1382             }
1383         }
1384         return err ? NULL : fname;
1385     }
1386 
1387     /* try workdir first */
1388     gretl_build_path(fname, paths.workdir, orig, NULL);
1389     err = gretl_test_fopen(fname, "r");
1390     if (!err) {
1391         /* got it */
1392         return fname;
1393     }
1394 
1395     if (script_dirs != NULL) {
1396         GList *dirs = g_list_last(script_dirs);
1397         int flags = script ? 0 : ADD_GDT;
1398         const char *gpath;
1399 
1400 #if SCRIPT_DIRS_DEBUG
1401         print_script_dirs();
1402 #endif
1403         while (dirs != NULL && !found) {
1404             strcpy(fname, orig);
1405             gpath = dirs->data;
1406             test = search_dir(fname, gpath, flags);
1407             if (test != NULL) {
1408                 found = 1;
1409             }
1410             dirs = dirs->prev;
1411         }
1412         if (found) {
1413             return fname;
1414         }
1415     }
1416 
1417     if (!found) {
1418         char trydir[MAXLEN];
1419         const char *gpath;
1420 
1421         strcpy(fname, orig);
1422 
1423         /* now try gretl installation dir */
1424         gpath = gretl_home();
1425 
1426         if (*gpath != '\0') {
1427             /* try searching some standard gretl paths */
1428             if (script) {
1429                 sprintf(trydir, "%sscripts", gpath);
1430                 test = search_dir(fname, trydir, SUBDIRS);
1431                 if (test != NULL) {
1432                     return fname;
1433                 } else {
1434                     strcpy(fname, orig);
1435                     sprintf(trydir, "%sfunctions", gpath);
1436                     test = search_dir(fname, trydir, ADD_GFN | SUBDIRS);
1437                     if (test != NULL) {
1438                         return fname;
1439                     }
1440                 }
1441             } else if (has_suffix(fname, ".bin")) {
1442                 /* database? */
1443                 sprintf(trydir, "%sdb", gpath);
1444                 test = search_dir(fname, trydir, 0);
1445                 if (test != NULL) {
1446                     return fname;
1447                 }
1448             } else {
1449                 /* data file */
1450                 sprintf(trydir, "%sdata", gpath);
1451                 test = search_dir(fname, trydir, ADD_GDT | SUBDIRS);
1452                 if (test != NULL) {
1453                     return fname;
1454                 }
1455             }
1456         }
1457 
1458         strcpy(fname, orig);
1459 
1460         /* now try user's personal filespace */
1461 #ifdef OS_OSX
1462         gpath = gretl_app_support_dir();
1463 #else
1464         gpath = gretl_dotdir();
1465 #endif
1466 
1467         if (*gpath != '\0') {
1468             /* try looking in ~/Library or dotdir */
1469             if (script) {
1470                 sprintf(trydir, "%sscripts", gpath);
1471                 test = search_dir(fname, trydir, SUBDIRS);
1472                 if (test != NULL) {
1473                     return fname;
1474                 } else {
1475                     strcpy(fname, orig);
1476                     sprintf(trydir, "%sfunctions", gpath);
1477                     test = search_dir(fname, trydir, ADD_GFN | SUBDIRS);
1478                     if (test != NULL) {
1479                         return fname;
1480                     }
1481                 }
1482             } else if (has_suffix(fname, ".bin")) {
1483                 /* database? */
1484                 sprintf(trydir, "%sdb", gpath);
1485                 test = search_dir(fname, trydir, 0);
1486                 if (test != NULL) {
1487                     return fname;
1488                 }
1489             } else {
1490                 /* data file? */
1491                 sprintf(trydir, "%sdata", gpath);
1492                 test = search_dir(fname, trydir, ADD_GDT | SUBDIRS);
1493                 if (test != NULL) {
1494                     return fname;
1495                 }
1496             }
1497         }
1498 
1499         strcpy(fname, orig);
1500         gpath = gretl_workdir();
1501 
1502         if (*gpath != '\0') {
1503             /* try looking in user's dir (and subdirs) */
1504             test = search_dir(fname, gpath, SUBDIRS);
1505             if (test != NULL) {
1506                 return fname;
1507             }
1508         }
1509 
1510         strcpy(fname, orig);
1511         gpath = maybe_get_default_workdir();
1512 
1513         if (gpath != NULL && *gpath != '\0') {
1514             /* try looking in default workdir? */
1515             test = search_dir(fname, gpath, SUBDIRS);
1516             if (test != NULL) {
1517                 return fname;
1518             }
1519         }
1520     }
1521 
1522 #ifdef WIN32
1523     /* try looking on the desktop? */
1524     if (1) {
1525         char *dtdir = desktop_path();
1526 
1527         strcpy(fname, orig);
1528         if (dtdir != NULL) {
1529             test = search_dir(fname, dtdir, 0);
1530             free(dtdir);
1531         }
1532         if (test != NULL) {
1533             return fname;
1534         }
1535     }
1536 #endif
1537 
1538     strcpy(fname, orig);
1539 
1540     gretl_error_clear();
1541 
1542     return NULL;
1543 }
1544 
1545 /* It is assumed here that @fname starts with "~/" */
1546 
gretl_prepend_homedir(const char * fname,int * err)1547 char *gretl_prepend_homedir (const char *fname, int *err)
1548 {
1549     char *homedir = getenv("HOME");
1550     char *ret = NULL;
1551 
1552     if (homedir != NULL) {
1553         ret = malloc(strlen(homedir) + strlen(fname));
1554         if (ret == NULL) {
1555             *err = E_ALLOC;
1556         } else {
1557             strcpy(ret, homedir);
1558             strcat(ret, fname + 1);
1559         }
1560     } else {
1561         *err = E_DATA;
1562     }
1563 
1564     return ret;
1565 }
1566 
substitute_homedir(char * fname)1567 static int substitute_homedir (char *fname)
1568 {
1569     char *homedir = getenv("HOME");
1570     int err = 0;
1571 
1572     if (homedir != NULL) {
1573         int len = strlen(fname);
1574         int homelen = strlen(homedir);
1575 
1576         if (len + homelen > MAXLEN) {
1577             err = 1;
1578         } else {
1579             char tmp[MAXLEN];
1580 
1581             strcpy(tmp, homedir);
1582             strcat(tmp, fname + 1);
1583             strcpy(fname, tmp);
1584         }
1585     }
1586 
1587     return err;
1588 }
1589 
get_gfn_special(char * fname)1590 static int get_gfn_special (char *fname)
1591 {
1592     int ok = 0;
1593 
1594     if (!strchr(fname, '/') && !strchr(fname, '\\')) {
1595         char *p, pkgname[64];
1596         char *pkgpath;
1597 
1598         *pkgname = '\0';
1599         strncat(pkgname, fname, 63);
1600         p = strstr(pkgname, ".gfn");
1601         *p = '\0';
1602         pkgpath = gretl_function_package_get_path(pkgname, PKG_ALL);
1603         if (pkgpath != NULL) {
1604             strcpy(fname, pkgpath);
1605             free(pkgpath);
1606             ok = 1;
1607         }
1608     }
1609 
1610     return ok;
1611 }
1612 
1613 /**
1614  * get_full_filename:
1615  * @fname: input filename.
1616  * @fullname: filename to be filled out: must be at least #MAXLEN bytes.
1617  * @opt: if OPT_S, treat as a script; if OPT_I we're responding
1618  * to the "include" command; if OPT_W, pass @fname through as is.
1619  *
1620  * Includes elementary path-searching: try adding various paths to the
1621  * given @fname, if appropriate, and see if it can be opened. For
1622  * internal gretl use.
1623  *
1624  * Returns: 0 on success, non-zero on error.
1625  */
1626 
get_full_filename(const char * fname,char * fullname,gretlopt opt)1627 int get_full_filename (const char *fname, char *fullname, gretlopt opt)
1628 {
1629     int script = (opt & (OPT_S | OPT_I))? 1 : 0;
1630     char *test = NULL;
1631     int err = 0;
1632 
1633     *fullname = '\0';
1634 
1635     if (fname == NULL || *fname == '\0') {
1636         return E_DATA;
1637     }
1638 
1639     strncat(fullname, fname, MAXLEN - 1);
1640 
1641     if (opt & OPT_W) {
1642         /* remote database: just use original name */
1643         return 0;
1644     }
1645 
1646     if (fullname[0] == '~' && fullname[1] == '/') {
1647         /* handle tilde == HOME */
1648         substitute_homedir(fullname);
1649     }
1650 
1651     if (g_path_is_absolute(fullname)) {
1652         goto test_open;
1653     }
1654 
1655     if (opt & OPT_I) {
1656         /* respect special "include" setting if present */
1657         char *ipath = getenv("GRETL_INCLUDE_PATH");
1658 
1659         if (ipath != NULL && *ipath != '\0') {
1660             gretl_build_path(fullname, ipath, fname, NULL);
1661             goto test_open;
1662         }
1663     }
1664 
1665     if (has_suffix(fullname, ".gfn") && get_gfn_special(fullname)) {
1666         /* checked for existence */
1667         return 0;
1668     }
1669 
1670     /* try a basic path search on this filename */
1671     test = gretl_addpath(fullname, script);
1672 
1673     gretl_normalize_path(fullname);
1674 
1675  test_open:
1676 
1677     if (!err && test == NULL) {
1678         err = gretl_test_fopen(fullname, "r");
1679         if (err) {
1680             /* ensure we return a gretl error code */
1681             err = E_FOPEN;
1682         }
1683     }
1684 
1685     if (test != NULL && (opt & OPT_S)) {
1686         /* If @test is non-NULL that means we actually found
1687            the file somewhere, so if it's a script we'll
1688            record the directory in which it was found.
1689         */
1690         gretl_set_script_dir(fullname);
1691     }
1692 
1693     return err;
1694 }
1695 
has_system_prefix(const char * fname,SearchType stype)1696 int has_system_prefix (const char *fname, SearchType stype)
1697 {
1698     const char *gretldir = gretl_home();
1699     int n = strlen(gretldir);
1700     int ret = 0;
1701 
1702     if (strlen(fname) < n) {
1703         return 0;
1704     }
1705 
1706     if (!strncmp(fname, gretldir, n)) {
1707         if (stype == DATA_SEARCH &&
1708             !strncmp(fname + n, "data", 4)) {
1709             ret = 1;
1710         } else if (stype == SCRIPT_SEARCH &&
1711                    !strncmp(fname + n, "scripts", 7)) {
1712             ret = 1;
1713         }
1714     }
1715 
1716     return ret;
1717 }
1718 
1719 enum paths_status_flags {
1720     STRING_TABLE_WRITTEN = 1 << 0
1721 };
1722 
set_gretl_plugpath(const char * path)1723 static void set_gretl_plugpath (const char *path)
1724 {
1725     *paths.plugpath = '\0';
1726 
1727 #if defined(WIN32) && defined(PKGBUILD)
1728     strcpy(paths.plugpath, path);
1729     strcat(paths.plugpath, PLUGIN_SFX);
1730 #else
1731 # ifdef LIBDIR
1732     /* respect the libdir set at compile time, e.g. /usr/lib or
1733        /usr/lib64
1734     */
1735     gretl_build_path(paths.plugpath, LIBDIR, PLUGIN_SFX, NULL);
1736 # else
1737 #  ifdef WIN32
1738     char *p = strstr(path, "\\share");
1739 #  else
1740     char *p = strstr(path, "/share");
1741 #  endif
1742 
1743     if (p != NULL) {
1744         /* back up a level */
1745         size_t len = p - path;
1746 
1747         strncat(paths.plugpath, path, len);
1748     } else {
1749         strcpy(paths.plugpath, path);
1750     }
1751     slash_terminate(paths.plugpath);
1752     strcat(paths.plugpath, "lib");
1753     slash_terminate(paths.plugpath);
1754     strcat(paths.plugpath, PLUGIN_SFX);
1755 # endif /* !LIBDIR */
1756 #endif /* !WIN32 */
1757 
1758     slash_terminate(paths.plugpath);
1759 }
1760 
set_gretl_binbase(const char * path)1761 static void set_gretl_binbase (const char *path)
1762 {
1763     sprintf(paths.binbase, "%sdb", path);
1764 }
1765 
1766 /* This should be called after we're fairly confident that we
1767    have the dotdir setting right */
1768 
set_extra_dot_paths(void)1769 static int set_extra_dot_paths (void)
1770 {
1771     char dirname[MAXLEN+128];
1772     size_t n;
1773     int err = 0;
1774 
1775     /* the personal function package directory */
1776     *dirname = '\0';
1777     gretl_build_path(dirname, paths.dotdir, "functions", NULL);
1778     gretl_mkdir(dirname);
1779 
1780     *paths.tramodir = '\0';
1781     *paths.x12adir = '\0';
1782 
1783 #if !defined(HAVE_TRAMO) && !defined(HAVE_X12A)
1784     return 0;
1785 #endif
1786 
1787     *dirname = '\0';
1788     strcpy(dirname, paths.dotdir);
1789     n = strlen(dirname);
1790 
1791     if (n > 0 && (dirname[n-1] == '\\' || dirname[n-1] == '/')) {
1792         dirname[n-1] = '\0';
1793     }
1794 
1795 #ifdef HAVE_X12A
1796     gretl_build_path(paths.x12adir, paths.dotdir, "x12arima", NULL);
1797     err = gretl_mkdir(paths.x12adir);
1798     if (err) {
1799         *paths.x12adir = '\0';
1800     }
1801 #endif
1802 
1803 #ifdef HAVE_TRAMO
1804     gretl_build_path(paths.tramodir, paths.dotdir, "tramo", NULL);
1805     if (gretl_mkdir(paths.tramodir)) {
1806         *paths.tramodir = '\0';
1807         return 1;
1808     }
1809 
1810     sprintf(dirname, "%s%coutput", paths.tramodir, SLASH);
1811     gretl_mkdir(dirname);
1812 
1813     sprintf(dirname, "%s%cgraph", paths.tramodir, SLASH);
1814     if (gretl_mkdir(dirname)) {
1815         *paths.tramodir = '\0';
1816         return 1;
1817     }
1818 
1819     sprintf(dirname, "%s%cgraph%cacf", paths.tramodir, SLASH, SLASH);
1820     gretl_mkdir(dirname);
1821     sprintf(dirname, "%s%cgraph%cfilters", paths.tramodir, SLASH, SLASH);
1822     gretl_mkdir(dirname);
1823     sprintf(dirname, "%s%cgraph%cforecast", paths.tramodir, SLASH, SLASH);
1824     gretl_mkdir(dirname);
1825     sprintf(dirname, "%s%cgraph%cseries", paths.tramodir, SLASH, SLASH);
1826     gretl_mkdir(dirname);
1827     sprintf(dirname, "%s%cgraph%cspectra", paths.tramodir, SLASH, SLASH);
1828     gretl_mkdir(dirname);
1829 #endif
1830 
1831     return err;
1832 }
1833 
set_builtin_path_strings(int update)1834 static void set_builtin_path_strings (int update)
1835 {
1836     gretl_insert_builtin_string("gretldir", paths.gretldir);
1837     gretl_insert_builtin_string("gnuplot",  paths.gnuplot);
1838     gretl_insert_builtin_string("x12a",     paths.x12a);
1839     gretl_insert_builtin_string("tramo",    paths.tramo);
1840 
1841     if (!update) {
1842         /* these only have to be done once */
1843         gretl_insert_builtin_string("dotdir",   paths.dotdir);
1844         gretl_insert_builtin_string("workdir",  paths.workdir);
1845         gretl_insert_builtin_string("x12adir",  paths.x12adir);
1846         gretl_insert_builtin_string("tramodir", paths.tramodir);
1847     }
1848 
1849     if (*paths.tramo != '\0') {
1850         char s[MAXLEN];
1851         int n;
1852 
1853         *s = '\0';
1854         strncat(s, paths.tramo, MAXLEN - 1);
1855         n = strlen(s);
1856 #ifdef WIN32
1857         if (n >= 9 && !strcmp(s + n - 9, "tramo.exe")) {
1858             strcpy(s + n - 9, "seats.exe");
1859             gretl_insert_builtin_string("seats", s);
1860             return;
1861         }
1862 #else
1863         if (n >= 5 && !strcmp(s + n - 5, "tramo")) {
1864             strcpy(s + n - 5, "seats");
1865             gretl_insert_builtin_string("seats", s);
1866         }
1867 #endif
1868     }
1869 }
1870 
gretl_home(void)1871 const char *gretl_home (void)
1872 {
1873     return paths.gretldir;
1874 }
1875 
gretl_bindir(void)1876 const char *gretl_bindir (void)
1877 {
1878     static char bindir[MAXLEN];
1879 
1880     if (*bindir == '\0') {
1881         char *p;
1882 
1883         strcpy(bindir, paths.gretldir);
1884         p = strstr(bindir, "share/gretl");
1885         if (p != NULL) {
1886             *p = '\0';
1887             strcat(p, "bin/");
1888         }
1889 #ifdef WIN32
1890         if (p == NULL) {
1891             p = strstr(bindir, "share\\gretl");
1892             if (p != NULL) {
1893                 *p = '\0';
1894                 strcat(p, "bin\\");
1895             }
1896         }
1897 #endif
1898     }
1899 
1900     return bindir;
1901 }
1902 
gretl_plugin_path(void)1903 const char *gretl_plugin_path (void)
1904 {
1905     static int set;
1906 
1907     if (!set) {
1908         char *epath = getenv("GRETL_PLUGIN_PATH");
1909 
1910         if (epath != NULL) {
1911             *paths.plugpath = '\0';
1912             strncat(paths.plugpath, epath, MAXLEN - 2);
1913             slash_terminate(paths.plugpath);
1914         }
1915 
1916 #if defined(LIBDIR) || defined(GRETL_PREFIX)
1917         /* if blank, try drawing on compiled-in values */
1918         if (*paths.plugpath == '\0') {
1919 # ifdef LIBDIR
1920             strcat(paths.plugpath, LIBDIR);
1921 # else
1922             strcat(paths.plugpath, GRETL_PREFIX);
1923             slash_terminate(paths.plugpath);
1924             strcat(paths.plugpath, "lib");
1925 # endif
1926             slash_terminate(paths.plugpath);
1927             strcat(paths.plugpath, PLUGIN_SFX);
1928             slash_terminate(paths.plugpath);
1929         }
1930 #endif /* LIBDIR or GRETL_PREFIX defined */
1931         set = 1;
1932     }
1933 
1934     return paths.plugpath;
1935 }
1936 
gretl_dotdir(void)1937 const char *gretl_dotdir (void)
1938 {
1939     return paths.dotdir;
1940 }
1941 
gretl_make_dotpath(const char * basename)1942 gchar *gretl_make_dotpath (const char *basename)
1943 {
1944     return g_build_filename(paths.dotdir, basename, NULL);
1945 }
1946 
gretl_workdir(void)1947 const char *gretl_workdir (void)
1948 {
1949     return paths.workdir;
1950 }
1951 
1952 #ifdef WIN32
1953 
win32_default_workdir(void)1954 static const char *win32_default_workdir (void)
1955 {
1956     static char default_workdir[MAXLEN];
1957     char *base = mydocs_path();
1958     const char *retval = NULL;
1959 
1960     if (base != NULL) {
1961         sprintf(default_workdir, "%s\\gretl\\", base);
1962         if (strcmp(default_workdir, paths.workdir)) {
1963             GDir *dir = gretl_opendir(default_workdir);
1964 
1965             if (dir != NULL) {
1966                 g_dir_close(dir);
1967                 retval = default_workdir;
1968             }
1969         }
1970         free(base);
1971     }
1972 
1973     return retval;
1974 }
1975 
1976 #else /* !WIN32 */
1977 
regular_default_workdir(void)1978 static const char *regular_default_workdir (void)
1979 {
1980     static char default_workdir[MAXLEN];
1981     char *home = getenv("HOME");
1982     const char *retval = NULL;
1983 
1984     if (home != NULL) {
1985         sprintf(default_workdir, "%s/gretl/", home);
1986         if (strcmp(default_workdir, paths.workdir)) {
1987             GDir *dir = gretl_opendir(default_workdir);
1988 
1989             if (dir != NULL) {
1990                 g_dir_close(dir);
1991                 retval = default_workdir;
1992             }
1993         }
1994     }
1995 
1996     return retval;
1997 }
1998 
1999 #endif /* WIN32 or not */
2000 
2001 /**
2002  * maybe_get_default_workdir:
2003  *
2004  * Figures the full path to the default value of the
2005  * user's gretl working directory; call this "defdir".
2006  *
2007  * If this defdir turns out to be the same as the
2008  * current gretl working directory, as would be returned
2009  * by gretl_workdir(), this function returns NULL,
2010  * otherwise it returns the defdir value.
2011  *
2012  * Returns: a path, or NULL.
2013  */
2014 
maybe_get_default_workdir(void)2015 const char *maybe_get_default_workdir (void)
2016 {
2017 #ifdef WIN32
2018     return win32_default_workdir();
2019 #else
2020     return regular_default_workdir();
2021 #endif
2022 }
2023 
validate_writedir(const char * dirname)2024 static int validate_writedir (const char *dirname)
2025 {
2026     int err = 0;
2027 
2028     if (*dirname == '\0') {
2029         gretl_errmsg_set(_("User directory is not set"));
2030         return E_DATA;
2031     }
2032 
2033     err = gretl_mkdir(dirname);
2034     if (err) {
2035         gretl_errmsg_sprintf( _("Couldn't create directory '%s'"), dirname);
2036     }
2037 
2038     if (!err) {
2039         /* ensure the directory is writable */
2040         char testname[FILENAME_MAX];
2041         FILE *fp;
2042 
2043         gretl_build_path(testname, dirname, "write.chk", NULL);
2044         fp = gretl_fopen(testname, "w");
2045         if (fp == NULL) {
2046             gretl_errmsg_sprintf(_("Couldn't write to '%s': "
2047                                    "gretl will not work properly!"),
2048                                  dirname);
2049             err = E_FOPEN;
2050         } else {
2051             fclose(fp);
2052             gretl_remove(testname);
2053         }
2054     }
2055 
2056     if (err) {
2057         set_gretl_alarm(1);
2058     }
2059 
2060     return err;
2061 }
2062 
set_gretl_workdir(const char * path)2063 static int set_gretl_workdir (const char *path)
2064 {
2065     GDir *test;
2066     int err = 0;
2067 
2068     errno = 0;
2069 
2070     test = gretl_opendir(path);
2071 
2072     if (test == NULL) {
2073         gretl_errmsg_set_from_errno(path, errno);
2074         fprintf(stderr, "set_gretl_work_dir: '%s': failed\n", path);
2075         err = E_FOPEN;
2076     } else {
2077         g_dir_close(test);
2078         strcpy(paths.workdir, path);
2079         slash_terminate(paths.workdir);
2080         gretl_insert_builtin_string("workdir", paths.workdir);
2081     }
2082 
2083     return err;
2084 }
2085 
gretl_gnuplot_path(void)2086 const char *gretl_gnuplot_path (void)
2087 {
2088     return paths.gnuplot;
2089 }
2090 
gretl_plotfile(void)2091 const char *gretl_plotfile (void)
2092 {
2093     return paths.plotfile;
2094 }
2095 
report_plot_written(PRN * prn)2096 void report_plot_written (PRN *prn)
2097 {
2098     if (prn != NULL) {
2099         pprintf(prn, _("wrote %s\n"), paths.plotfile);
2100     }
2101 }
2102 
gretl_binbase(void)2103 const char *gretl_binbase (void)
2104 {
2105     return paths.binbase;
2106 }
2107 
gretl_tramo(void)2108 const char *gretl_tramo (void)
2109 {
2110     return paths.tramo;
2111 }
2112 
gretl_tramo_dir(void)2113 const char *gretl_tramo_dir (void)
2114 {
2115     return paths.tramodir;
2116 }
2117 
gretl_x12_arima(void)2118 const char *gretl_x12_arima (void)
2119 {
2120     return paths.x12a;
2121 }
2122 
gretl_x12_arima_dir(void)2123 const char *gretl_x12_arima_dir (void)
2124 {
2125     return paths.x12adir;
2126 }
2127 
gretl_x12_is_x13(void)2128 int gretl_x12_is_x13 (void)
2129 {
2130     return strstr(paths.x12a, "x13") != NULL;
2131 }
2132 
2133 #ifdef WIN32
2134 
2135 /* try to avoid using a stale value saved to .gretl2rc */
2136 
R_path_try_registry(int which,char * targ)2137 static void R_path_try_registry (int which, char *targ)
2138 {
2139     char tmp[MAX_PATH];
2140     int err;
2141 
2142     err = R_path_from_registry(tmp, which);
2143 
2144     if (!err) {
2145         *targ = '\0';
2146         strncat(targ, tmp, MAXLEN - 1);
2147     }
2148 }
2149 
2150 #endif
2151 
gretl_rbin_path(void)2152 const char *gretl_rbin_path (void)
2153 {
2154 #ifdef WIN32
2155     static int checked;
2156 
2157     if (!checked) {
2158         R_path_try_registry(REXE, paths.rbinpath);
2159         checked = 1;
2160     }
2161 #endif
2162 
2163 #if 0
2164     fprintf(stderr, "gretl_rbin_path: '%s'\n", paths.rbinpath);
2165 #endif
2166 
2167     return paths.rbinpath;
2168 }
2169 
gretl_rlib_path(void)2170 const char *gretl_rlib_path (void)
2171 {
2172 #ifdef WIN32
2173     static int checked;
2174 
2175     if (!checked) {
2176         R_path_try_registry(RLIB, paths.rlibpath);
2177         checked = 1;
2178     }
2179 #endif
2180 
2181 #if 0
2182     fprintf(stderr, "gretl_rlib_path: '%s'\n", paths.rlibpath);
2183 #endif
2184 
2185     return paths.rlibpath;
2186 }
2187 
gretl_oxl_path(void)2188 const char *gretl_oxl_path (void)
2189 {
2190     return paths.oxlpath;
2191 }
2192 
gretl_octave_path(void)2193 const char *gretl_octave_path (void)
2194 {
2195     return paths.octpath;
2196 }
2197 
gretl_stata_path(void)2198 const char *gretl_stata_path (void)
2199 {
2200     return paths.statapath;
2201 }
2202 
gretl_python_path(void)2203 const char *gretl_python_path (void)
2204 {
2205     return paths.pypath;
2206 }
2207 
gretl_julia_path(void)2208 const char *gretl_julia_path (void)
2209 {
2210     return paths.jlpath;
2211 }
2212 
gretl_lpsolve_path(void)2213 const char *gretl_lpsolve_path (void)
2214 {
2215     return paths.lppath;
2216 }
2217 
gretl_mpi_hosts(void)2218 const char *gretl_mpi_hosts (void)
2219 {
2220     return paths.mpi_hosts;
2221 }
2222 
gretl_mpiexec(void)2223 const char *gretl_mpiexec (void)
2224 {
2225     return paths.mpiexec;
2226 }
2227 
pathcomp(gconstpointer a,gconstpointer b)2228 static gint pathcomp (gconstpointer a,
2229                       gconstpointer b)
2230 {
2231     return strcmp((const char *) a, (const char *) b);
2232 }
2233 
gretl_set_script_dir(const char * s)2234 void gretl_set_script_dir (const char *s)
2235 {
2236     gchar *add = g_path_get_dirname(s);
2237     GList *L = g_list_find_custom(script_dirs, add, pathcomp);
2238 
2239     if (L != NULL) {
2240         /* this directory is already in the list */
2241         if (L->next != NULL) {
2242             /* delete intervening record */
2243             g_free(L->next->data);
2244             script_dirs = g_list_delete_link(script_dirs, L->next);
2245         }
2246         g_free(add);
2247     } else {
2248         script_dirs = g_list_append(script_dirs, add);
2249     }
2250 }
2251 
gretl_script_dirs_cleanup(void)2252 void gretl_script_dirs_cleanup (void)
2253 {
2254     if (script_dirs != NULL) {
2255 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 28
2256         GList *l0 = g_list_first(script_dirs);
2257 
2258         while (l0) {
2259             g_free(l0->data);
2260             l0 = l0->next;
2261         }
2262         g_list_free(script_dirs);
2263 #else
2264         g_list_free_full(script_dirs, g_free);
2265 #endif
2266         script_dirs = NULL;
2267     }
2268 }
2269 
gretl_png_font(void)2270 const char *gretl_png_font (void)
2271 {
2272     return paths.pngfont;
2273 }
2274 
set_gretl_png_font(const char * s)2275 void set_gretl_png_font (const char *s)
2276 {
2277     strcpy(paths.pngfont, s);
2278 }
2279 
set_string_table_written(void)2280 void set_string_table_written (void)
2281 {
2282     paths.status |= STRING_TABLE_WRITTEN;
2283 }
2284 
gretl_string_table_written(void)2285 int gretl_string_table_written (void)
2286 {
2287     int ret = 0;
2288 
2289     if (paths.status & STRING_TABLE_WRITTEN) ret = 1;
2290 
2291     paths.status &= ~STRING_TABLE_WRITTEN;
2292 
2293     return ret;
2294 }
2295 
show_paths(void)2296 void show_paths (void)
2297 {
2298     printf(_("gretl: using these basic search paths:\n"));
2299     printf("gretldir: %s\n", paths.gretldir);
2300     printf("workdir: %s\n", paths.workdir);
2301     printf("dotdir: %s\n", paths.dotdir);
2302     printf("gnuplot: %s\n", paths.gnuplot);
2303 }
2304 
2305 #ifdef WIN32
2306 
rightmost(char * s1,char * s2)2307 static char *rightmost (char *s1, char *s2)
2308 {
2309     if (s1 == NULL) {
2310         return s2;
2311     } else if (s2 == NULL) {
2312         return s1;
2313     } else {
2314         return (s2 - s1 > 0)? s2 : s1;
2315     }
2316 }
2317 
getsep(const char * s)2318 static char getsep (const char *s)
2319 {
2320     int bak = 0, fwd = 0;
2321 
2322     while (*s) {
2323         if (*s == '\\') {
2324             bak++;
2325         } else if (*s == '/') {
2326             fwd++;
2327         }
2328         s++;
2329     }
2330 
2331     return fwd > bak ? '/' : '\\';
2332 }
2333 
rslashpos(const char * s)2334 static char *rslashpos (const char *s)
2335 {
2336     char *p1 = strrchr(s, '\\');
2337     char *p2 = strrchr(s, '/');
2338 
2339     return rightmost(p1, p2);
2340 }
2341 
slash_terminated(const char * s,int n)2342 static int slash_terminated (const char *s, int n)
2343 {
2344     return s[n-1] == '\\' || s[n-1] == '/';
2345 }
2346 
win32_set_gretldir(void)2347 void win32_set_gretldir (void)
2348 {
2349     gchar *pkgdir;
2350 
2351     *paths.gretldir = '\0';
2352 
2353     pkgdir = g_win32_get_package_installation_directory_of_module(NULL);
2354 
2355     if (pkgdir != NULL) {
2356         strncat(paths.gretldir, pkgdir, MAXLEN - 1);
2357         slash_terminate(paths.gretldir);
2358         g_free(pkgdir);
2359     }
2360 
2361 # ifdef PKGBUILD
2362     if (*paths.gretldir == '\0') {
2363         /* try the registry? */
2364         char tmp[MAXLEN];
2365         int err;
2366 
2367         err = read_reg_val(HKEY_LOCAL_MACHINE, "gretl", "gretldir", tmp);
2368         if (!err) {
2369             strcpy(paths.gretldir, tmp);
2370             slash_terminate(paths.gretldir);
2371         }
2372     }
2373     if (*paths.gretldir != '\0') {
2374         set_gretlnet_filename(paths.gretldir);
2375     }
2376 # else
2377     /* a non-pkgbuild Windows build */
2378     if (*paths.gretldir != '\0') {
2379         /* we need to append unix-style sharedir */
2380         strcat(paths.gretldir, "share");
2381         slash_terminate(paths.gretldir);
2382         strcat(paths.gretldir, "gretl");
2383         slash_terminate(paths.gretldir);
2384     }
2385 # endif
2386 
2387     if (*paths.gretldir == '\0') {
2388         fprintf(stderr, "win32_set_gretldir: haven't got gretldir yet!\n");
2389     }
2390 }
2391 
2392 #else /* !WIN32 */
2393 
2394 /* We have paths.gretldir in place: now test it by seeing if we can
2395    open the the GPL file "COPYING", which definitely should be in that
2396    directory.  If that doesn't work, try some remedial measures.
2397    Note, @config_path is the path garnered from the config file,
2398    which we may or may not have used to write paths.gretldir (and
2399    which may indeed be an empty string).
2400 */
2401 
check_gretldir(char * config_path)2402 static void check_gretldir (char *config_path)
2403 {
2404     char testname[FILENAME_MAX];
2405     FILE *fp;
2406     int gotit = 0;
2407 
2408     sprintf(testname, "%sCOPYING", paths.gretldir);
2409     fp = gretl_fopen(testname, "r");
2410 
2411     if (fp != NULL) {
2412         /* should be fine as is */
2413         fclose(fp);
2414         gotit = 1;
2415     } else if (*config_path != '\0') {
2416         slash_terminate(config_path);
2417         if (strcmp(config_path, paths.gretldir)) {
2418             /* we weren't using the config-file version: try it now */
2419             sprintf(testname, "%sCOPYING", config_path);
2420             fp = gretl_fopen(testname, "r");
2421             if (fp != NULL) {
2422                 strcpy(paths.gretldir, config_path);
2423                 fclose(fp);
2424                 gotit = 1;
2425             }
2426         }
2427     }
2428 
2429     if (!gotit && !gretl_in_tool_mode()) {
2430         /* we're messed up; try to recover */
2431         pid_t pid = getpid();
2432         gchar *proc_exe;
2433         const char *s;
2434         ssize_t nr;
2435 
2436         proc_exe = g_strdup_printf("/proc/%d/exe", pid);
2437         nr = readlink(proc_exe, testname, FILENAME_MAX - 1);
2438 
2439         if (nr > 0) {
2440             testname[nr] = '\0';
2441             fprintf(stderr, "gretl is process %d, '%s'\n", (int) pid, testname);
2442             /* should be something like /foo/bar/bin/gretl; we
2443                want the /foo/bar bit to append to
2444             */
2445             s = strstr(testname, "bin/gretl");
2446             if (s != NULL) {
2447                 *paths.gretldir = '\0';
2448                 strncat(paths.gretldir, testname, s - testname);
2449                 strcat(paths.gretldir, "share/gretl/");
2450                 fprintf(stderr, "gretldir is maybe '%s'?\n",
2451                         paths.gretldir);
2452             }
2453         }
2454 
2455         g_free(proc_exe);
2456     }
2457 }
2458 
2459 #endif
2460 
2461 /* Called at start-up only: the @dirname argument is the value taken
2462    from the config file or registry.  In case we end up using a value
2463    other than the incoming one, sync back to @dirname.
2464 */
2465 
initialize_gretldir(char * dirname,gretlopt opt)2466 static void initialize_gretldir (char *dirname, gretlopt opt)
2467 {
2468     char *ghome = getenv("GRETL_HOME");
2469     int err = 0;
2470 
2471     if (ghome != NULL) {
2472         /* environment setting, if any, takes precedence */
2473         strcpy(paths.gretldir, ghome);
2474         slash_terminate(paths.gretldir);
2475     } else if (dirname != NULL && *dirname != '\0' &&
2476                *paths.gretldir == '\0') {
2477         /* use value from config/registry, unless we already got
2478            a value somehow */
2479         strcpy(paths.gretldir, dirname);
2480         slash_terminate(paths.gretldir);
2481     }
2482 
2483     if (*paths.gretldir == '\0') {
2484 #ifdef WIN32
2485         /* fall back on installation-time default */
2486         char *progfiles = program_files_path();
2487 
2488         sprintf(paths.gretldir, "%s\\gretl\\", progfiles);
2489         free(progfiles);
2490 #else
2491         /* use the compile-time value */
2492         strcpy(paths.gretldir, GRETL_PREFIX);
2493         strcat(paths.gretldir, "/share/gretl/");
2494 #endif
2495     }
2496 
2497 #ifndef WIN32
2498     check_gretldir(dirname);
2499 #endif
2500 
2501     if (!err) {
2502         set_helpfile_option(opt);
2503         set_gretl_plugpath(paths.gretldir);
2504         set_gretl_binbase(paths.gretldir);
2505     }
2506 
2507     strcpy(dirname, paths.gretldir);
2508 }
2509 
2510 /**
2511  * set_gretl_plugin_path:
2512  * @path: path to the gretl plugins.
2513  *
2514  * For use by third-party code: the purpose of this function
2515  * is to ensure that libgretl can find its plugins.
2516  *
2517  * @prefix, if given, should be the path under which the plugins
2518  * are installed. On a unix-type system this might be, for example,
2519  * /usr/local/lib/gretl-gtk2; on MS Windows it might be
2520  * c:\program files\gretl\plugins.
2521  **/
2522 
set_gretl_plugin_path(const char * path)2523 void set_gretl_plugin_path (const char *path)
2524 {
2525     if (path != NULL) {
2526         *paths.plugpath = '\0';
2527         strncat(paths.plugpath, path, MAXLEN - 2);
2528         slash_terminate(paths.plugpath);
2529     }
2530 }
2531 
gretl_set_path_by_name(const char * name,const char * path)2532 int gretl_set_path_by_name (const char *name, const char *path)
2533 {
2534     char *targ = NULL;
2535     int builtin = 0;
2536 
2537     if (name == NULL || path == NULL) {
2538         return 1;
2539     } else if (!strcmp(name, "workdir")) {
2540         return set_gretl_workdir(path);
2541     } else if (!strcmp(name, "gnuplot")) {
2542         targ = paths.gnuplot;
2543     } else if (!strcmp(name, "plotfile")) {
2544         targ = paths.plotfile;
2545     } else if (!strcmp(name, "tramo")) {
2546         targ = paths.tramo;
2547         builtin = 1;
2548     } else if (!strcmp(name, "x12a")) {
2549         targ = paths.x12a;
2550         builtin = 1;
2551     } else {
2552         fprintf(stderr, "gretl_set_path_by_name: target '%s' not recognized\n",
2553                 name);
2554         return 1;
2555     }
2556 
2557     if (targ != NULL) {
2558         *targ = '\0';
2559         strncat(targ, path, MAXLEN - 2);
2560         if (builtin) {
2561             gretl_insert_builtin_string(name, targ);
2562         }
2563     }
2564 
2565     return 0;
2566 }
2567 
2568 /* Called at start-up only: set the "hidden" working dir,
2569    which is not user-configurable.
2570 */
2571 
initialize_dotdir(void)2572 static int initialize_dotdir (void)
2573 {
2574     char *dirname;
2575     int err = 0;
2576 
2577     *paths.dotdir = '\0';
2578 
2579 #ifdef WIN32
2580     dirname = appdata_path();
2581     if (dirname != NULL) {
2582         sprintf(paths.dotdir, "%s\\gretl\\", dirname);
2583         free(dirname);
2584     } else {
2585         sprintf(paths.dotdir, "%s\\user\\", paths.gretldir);
2586     }
2587 #else
2588     dirname = getenv("HOME");
2589     if (dirname != NULL) {
2590         sprintf(paths.dotdir, "%s/.gretl/", dirname);
2591     }
2592 #endif
2593 
2594     err = validate_writedir(paths.dotdir);
2595 
2596     if (err) {
2597         *paths.x12adir = '\0';
2598         *paths.tramodir = '\0';
2599     } else {
2600         /* these paths depend on dotdir */
2601         err = set_extra_dot_paths();
2602     }
2603 
2604     return err;
2605 }
2606 
2607 enum {
2608     PATH_NEEDS_SLASH = 1 << 0,
2609     PATH_BLANK_OK    = 1 << 1
2610 };
2611 
2612 /* Updating a gretl paths element: transcribe the new value unless it
2613    is unchanged; if it's a directory string that needs to be
2614    slash-terminated, check that; return 1 if any change was made to
2615    the internally recorded value, @targ, otherwise return 0.  Note
2616    that we ignore empty @src unless the PATH_BLANK_OK flag is given.
2617 */
2618 
maybe_transcribe_path(char * targ,char * src,int flags)2619 static int maybe_transcribe_path (char *targ, char *src, int flags)
2620 {
2621     int ret = 0;
2622 
2623     if (*src == '\0' && (flags & PATH_BLANK_OK)) {
2624         if (*targ != '\0') {
2625             *targ = '\0';
2626             ret = 1;
2627         }
2628     } else if (*src != '\0') {
2629         if (flags & PATH_NEEDS_SLASH) {
2630             slash_terminate(src);
2631         }
2632         if (strcmp(src, targ)) {
2633             strcpy(targ, src);
2634             ret = 1;
2635         }
2636     } else {
2637         /* back-sync */
2638         strcpy(src, targ);
2639     }
2640 
2641     return ret;
2642 }
2643 
2644 #define CFG_DEBUG 0
2645 
2646 /* gretl_update_paths is called from the GUI preferences dialog. The
2647    internal path elements that can be set in this way are:
2648 
2649    gretldir
2650    gnuplot (but not for MS Windows package)
2651    tramo, x12a, rbinpath, rlibpath, oxlpath, octpath, statapath,
2652      pypath, jlpath, lppath
2653 
2654    * paths.workdir is updated via the separate working directory
2655      dialog
2656 
2657    * paths.pngfont is updated separately via the plot editing
2658      dialog
2659 
2660    The @opt argument can include OPT_N to force use of the English-
2661    language help file where this would not be the default.
2662 */
2663 
gretl_update_paths(ConfigPaths * cpaths,gretlopt opt)2664 int gretl_update_paths (ConfigPaths *cpaths, gretlopt opt)
2665 {
2666     int ndelta = 0;
2667 
2668     if (maybe_transcribe_path(paths.gretldir, cpaths->gretldir,
2669                               PATH_NEEDS_SLASH)) {
2670         set_helpfile_option(opt);
2671         set_gretl_plugpath(paths.gretldir);
2672         ndelta++;
2673     }
2674 
2675 #if !defined(WIN32) || !defined(PKGBUILD)
2676     /* gnuplot path: this is set immutably at start-up in the
2677        gretl for Windows package */
2678     ndelta += maybe_transcribe_path(paths.gnuplot, cpaths->gnuplot, 0);
2679 #endif
2680 
2681     /* other external programs */
2682     ndelta += maybe_transcribe_path(paths.x12a, cpaths->x12a, 0);
2683     ndelta += maybe_transcribe_path(paths.tramo, cpaths->tramo, 0);
2684     ndelta += maybe_transcribe_path(paths.rbinpath, cpaths->rbinpath, 0);
2685     ndelta += maybe_transcribe_path(paths.oxlpath, cpaths->oxlpath, 0);
2686     ndelta += maybe_transcribe_path(paths.octpath, cpaths->octpath, 0);
2687     ndelta += maybe_transcribe_path(paths.statapath, cpaths->statapath, 0);
2688     ndelta += maybe_transcribe_path(paths.pypath, cpaths->pypath, 0);
2689     ndelta += maybe_transcribe_path(paths.jlpath, cpaths->jlpath, 0);
2690     ndelta += maybe_transcribe_path(paths.lppath, cpaths->lppath, 0);
2691 
2692 #ifdef HAVE_MPI
2693     ndelta += maybe_transcribe_path(paths.mpiexec, cpaths->mpiexec, 0);
2694     ndelta += maybe_transcribe_path(paths.mpi_hosts, cpaths->mpi_hosts,
2695                                     PATH_BLANK_OK);
2696 #endif
2697 
2698 #ifdef USE_RLIB
2699     if (maybe_transcribe_path(paths.rlibpath, cpaths->rlibpath, 0)) {
2700         gretl_R_reset_error();
2701         ndelta++;
2702     }
2703 #endif
2704 
2705     if (ndelta > 0) {
2706         /* we changed at least one thing that should be
2707            recorded in the builtin path strings */
2708         set_builtin_path_strings(1);
2709     }
2710 
2711 #if CFG_DEBUG
2712     fprintf(stderr, "gretl_update_paths: ndelta = %d\n", ndelta);
2713 #endif
2714 
2715     return 0;
2716 }
2717 
2718 #ifdef WIN32
2719 
2720 /* MS Windows variants of defaults for any paths that
2721    we need that were not found in the Windows registry
2722    (or network config file).
2723 */
2724 
load_default_workdir(char * targ)2725 static void load_default_workdir (char *targ)
2726 {
2727     char *home = mydocs_path();
2728 
2729     if (home != NULL) {
2730         sprintf(targ, "%s\\gretl\\", home);
2731         free(home);
2732     } else {
2733         sprintf(targ, "%suser\\", paths.gretldir);
2734     }
2735 }
2736 
load_default_path(char * targ)2737 static void load_default_path (char *targ)
2738 {
2739     char *progfiles = NULL;
2740     char *pfx86 = NULL;
2741 
2742 #ifndef PKGBUILD
2743     if (targ == paths.gnuplot) {
2744         sprintf(targ, "%swgnuplot.exe", gretl_bindir());
2745         return;
2746     }
2747 #endif
2748 
2749     progfiles = program_files_path();
2750     pfx86 = program_files_x86_path();
2751 
2752     if (targ == paths.workdir) {
2753         load_default_workdir(targ);
2754     } else if (targ == paths.x12a) {
2755         sprintf(targ, "%s\\x13as\\x13as.exe", progfiles);
2756     } else if (targ == paths.tramo) {
2757         sprintf(targ, "%s\\tramo\\tramo.exe", pfx86);
2758     } else if (targ == paths.rbinpath) {
2759         R_path_from_registry(targ, REXE);
2760     } else if (targ == paths.rlibpath) {
2761         R_path_from_registry(targ, RLIB);
2762     } else if (targ == paths.oxlpath) {
2763         sprintf(targ, "%s\\OxMetrics8\\Ox\\bin\\oxl.exe", progfiles);
2764     } else if (targ == paths.octpath) {
2765         strcpy(targ, "C:\\Octave-3.6.4\\bin\\octave.exe");
2766     } else if (targ == paths.statapath) {
2767         sprintf(targ, "%s\\Stata\\stata.exe", progfiles);
2768     } else if (targ == paths.pypath) {
2769         strcpy(targ, "python.exe");
2770     } else if (targ == paths.jlpath) {
2771         strcpy(targ, "julia.exe");
2772     } else if (targ == paths.lppath) {
2773 	strcpy(targ, "lpsolve55.dll");
2774     } else if (targ == paths.mpiexec) {
2775         strcpy(targ, "mpiexec.exe");
2776     } else if (targ == paths.mpi_hosts) {
2777         *targ = '\0';
2778     } else if (targ == paths.pngfont) {
2779         if (chinese_locale()) {
2780             strcpy(targ, "SimSun 8");
2781         } else if (japanese_locale()) {
2782             strcpy(targ, "Meiryo 8");
2783         } else {
2784             strcpy(targ, "verdana 8");
2785         }
2786     }
2787 
2788     free(progfiles);
2789     free(pfx86);
2790 }
2791 
2792 # if CFG_DEBUG
2793 
show_paths_on_stderr(void)2794 static void show_paths_on_stderr (void)
2795 {
2796     fprintf(stderr, "after gretl_set_paths:\n");
2797     fprintf(stderr, " gretldir = '%s'\n", paths.gretldir);
2798     fprintf(stderr, " workdir = '%s'\n", paths.workdir);
2799     fprintf(stderr, " dotdir = '%s'\n", paths.dotdir);
2800     fprintf(stderr, " gnuplot = '%s'\n", paths.gnuplot);
2801 }
2802 
2803 # endif
2804 
2805 #else /* !WIN32 */
2806 
2807 /* unix-type variants of defaults for any paths that we need
2808    that were not found in the gretl config file.
2809 */
2810 
load_default_workdir(char * targ)2811 static void load_default_workdir (char *targ)
2812 {
2813     char *home = getenv("HOME");
2814 
2815     if (home != NULL) {
2816         sprintf(targ, "%s/gretl/", home);
2817     } else {
2818         home = getenv("GRETL_WORKDIR");
2819         if (home != NULL) {
2820             strcpy(targ, home);
2821         } else {
2822             gretl_path_compose(targ, MAXLEN, paths.gretldir, "user/");
2823         }
2824     }
2825 }
2826 
load_default_path(char * targ)2827 static void load_default_path (char *targ)
2828 {
2829 #ifdef OS_OSX
2830     const char *app_paths[] = {
2831         "/Applications/OxMetrics8/ox/bin/oxl",
2832         "/Applications/Octave.app/Contents/Resources/bin/octave",
2833         "/Applications/Stata/Stata.app/Contents/MacOS/Stata"
2834     };
2835 #else
2836     const char *app_paths[] = {
2837         "oxl",
2838         "octave",
2839         "stata"
2840     };
2841 #endif
2842 
2843     if (targ == paths.workdir) {
2844         load_default_workdir(targ);
2845     } else if (targ == paths.gnuplot) {
2846 #if defined(OS_OSX) && defined(PKGBUILD)
2847         sprintf(targ, "%sgnuplot", gretl_bindir());
2848 #else
2849         strcpy(targ, "gnuplot");
2850 #endif
2851     } else if (targ == paths.x12a) {
2852 #ifdef HAVE_X12A
2853         strcpy(targ, "x12a");
2854 #else
2855         *targ = '\0';
2856 #endif
2857     } else if (targ == paths.tramo) {
2858 #ifdef HAVE_TRAMO
2859         strcpy(targ, "tramo");
2860 #else
2861         *targ = '\0';
2862 #endif
2863     } else if (targ == paths.rbinpath) {
2864         strcpy(paths.rbinpath, "R");
2865     } else if (targ == paths.rlibpath) {
2866 #ifdef RLIBPATH
2867         strcpy(paths.rlibpath, RLIBPATH);
2868 #else
2869         *paths.rlibpath = '\0';
2870 #endif
2871     } else if (targ == paths.oxlpath) {
2872         strcpy(paths.oxlpath, app_paths[0]);
2873     } else if (targ == paths.octpath) {
2874         strcpy(paths.octpath, app_paths[1]);
2875     } else if (targ == paths.statapath) {
2876         strcpy(paths.statapath, app_paths[2]);
2877     } else if (targ == paths.pypath) {
2878         strcpy(paths.pypath, "python");
2879     } else if (targ == paths.jlpath) {
2880         strcpy(paths.jlpath, "julia");
2881     } else if (targ == paths.lppath) {
2882 #if defined(OS_OSX)
2883         strcpy(paths.lppath, "liblpsolve55.dylib");
2884 #else
2885         strcpy(paths.lppath, "liblpsolve55.so");
2886 #endif
2887     } else if (targ == paths.mpiexec) {
2888 #if defined(OS_OSX)
2889         strcpy(paths.mpiexec, "/opt/openmpi/bin/mpiexec");
2890 #else
2891         strcpy(paths.mpiexec, "mpiexec");
2892 #endif
2893     } else if (targ == paths.mpi_hosts) {
2894         *paths.mpi_hosts = '\0';
2895     } else if (targ == paths.pngfont) {
2896 #if defined(OS_OSX)
2897         strcpy(targ, "Sans 10"); /* was 13, why? */
2898 #else
2899         if (chinese_locale()) {
2900             strcpy(targ, "NSimSun 10");
2901         } else {
2902             strcpy(targ, "Vera 9");
2903         }
2904 #endif
2905     }
2906 }
2907 
2908 #endif /* WIN32 or not */
2909 
add_slash(char * s)2910 int add_slash (char *s)
2911 {
2912     if (s[strlen(s)-1] != SLASH) {
2913         strcat(s, SLASHSTR);
2914         return 1;
2915     }
2916 
2917     return 0;
2918 }
2919 
path_init(char * targ,char * src,int needs_slash)2920 static void path_init (char *targ, char *src, int needs_slash)
2921 {
2922     if (*src) {
2923         strcpy(targ, src);
2924         if (needs_slash && slash_terminate(targ)) {
2925             strcpy(src, targ);
2926         }
2927     } else {
2928         load_default_path(targ);
2929         strcpy(src, targ);
2930     }
2931 }
2932 
2933 /* Set paths, falling back to defaults if no value has been supplied.
2934    We do this only at startup.  If the path that we record differs
2935    from that given in @cpaths, sync the value back to @cpaths
2936    (via path_init, above).
2937 */
2938 
copy_paths_with_fallback(ConfigPaths * cpaths)2939 static void copy_paths_with_fallback (ConfigPaths *cpaths)
2940 {
2941     /* working directory */
2942     path_init(paths.workdir, cpaths->workdir, 1);
2943 
2944     /* gnuplot */
2945 #if defined(WIN32) && defined(PKGBUILD)
2946     /* "hard-wired" case for Windows package */
2947     sprintf(paths.gnuplot, "%swgnuplot.exe", paths.gretldir);
2948 #else
2949     path_init(paths.gnuplot, cpaths->gnuplot, 0);
2950 #endif
2951 
2952     /* other external programs */
2953     path_init(paths.x12a, cpaths->x12a, 0);
2954     path_init(paths.tramo, cpaths->tramo, 0);
2955     path_init(paths.rbinpath, cpaths->rbinpath, 0);
2956     path_init(paths.rlibpath, cpaths->rlibpath, 0);
2957     path_init(paths.oxlpath, cpaths->oxlpath, 0);
2958     path_init(paths.octpath, cpaths->octpath, 0);
2959     path_init(paths.statapath, cpaths->statapath, 0);
2960     path_init(paths.pypath, cpaths->pypath, 0);
2961     path_init(paths.jlpath, cpaths->jlpath, 0);
2962     path_init(paths.lppath, cpaths->lppath, 0);
2963     path_init(paths.mpiexec, cpaths->mpiexec, 0);
2964     path_init(paths.mpi_hosts, cpaths->mpi_hosts, 0);
2965 
2966     /* graphing font */
2967     path_init(paths.pngfont, cpaths->pngfont, 0);
2968 }
2969 
2970 /* This is called after reading the gretl config file at startup
2971    (and only then).  Subsequent updates to paths via the GUI (if any)
2972    are handled by the function gretl_update_paths().
2973 
2974    The no_dotdir member of cpaths is used only when gretlcli is
2975    operating in "slave" mode (e.g. under a webserver). It forces gretl
2976    to use paths.workdir as the "dotdir" rather than using a directory
2977    under the executing user's HOME.  See
2978    http://gretl.sourceforge.net/slave/
2979 */
2980 
gretl_set_paths(ConfigPaths * cpaths)2981 int gretl_set_paths (ConfigPaths *cpaths)
2982 {
2983     int err0 = 0, err1 = 0;
2984     int retval = 0;
2985 
2986     *paths.workdir = '\0';
2987     *paths.plotfile = '\0';
2988 
2989     initialize_gretldir(cpaths->gretldir, OPT_NONE);
2990 
2991     if (!cpaths->no_dotdir) {
2992         err0 = initialize_dotdir();
2993     }
2994 
2995     copy_paths_with_fallback(cpaths);
2996 
2997     if (cpaths->no_dotdir) {
2998         strcpy(paths.dotdir, paths.workdir);
2999     }
3000 
3001     if (strcmp(paths.dotdir, paths.workdir)) {
3002         err1 = validate_writedir(paths.workdir);
3003         if (err1) {
3004             /* try falling back on the default working dir */
3005             const char *defpath = maybe_get_default_workdir();
3006 
3007             if (defpath != NULL && *defpath != '\0' &&
3008                 strcmp(defpath, paths.workdir)) {
3009                 err1 = validate_writedir(defpath);
3010                 if (err1 == 0) {
3011                     strcpy(paths.workdir, defpath);
3012                 }
3013             }
3014         }
3015     }
3016 
3017     set_builtin_path_strings(0);
3018     set_gretl_tex_preamble();
3019 
3020     retval = (err0)? err0 : err1;
3021 
3022 #if CFG_DEBUG
3023     fprintf(stderr, "gretl_set_paths: returning %d\n", retval);
3024 # ifdef WIN32
3025     show_paths_on_stderr();
3026 # endif
3027 #endif
3028 
3029     return retval;
3030 }
3031 
3032 /* For writing a file, name given by user: if the path is not
3033    absolute, switch to the gretl "workdir" unless @fname begins
3034    with '~' in which case we switch to the user's HOME.
3035 */
3036 
gretl_maybe_switch_dir(const char * fname)3037 const char *gretl_maybe_switch_dir (const char *fname)
3038 {
3039     if (fname[0] == '~' && fname[1] == '/') {
3040         char *home = getenv("HOME");
3041 
3042         if (home != NULL && gretl_chdir(home) == 0) {
3043             fname += 2;
3044         }
3045     } else if (!g_path_is_absolute(fname)) {
3046         gretl_chdir(paths.workdir);
3047     }
3048 
3049     return fname;
3050 }
3051 
3052 /**
3053  * gretl_maybe_prepend_dir:
3054  * @fname: the original filename, which should be in a
3055  * location of length FILENAME_MAX.
3056  *
3057  * If @fname starts with the construction "~/" to indicate
3058  * the user's HOME, replace this with the full path to that
3059  * directory.  Otherwise, if @fname is not already an
3060  * absolute path, prepend the user's gretl working directory.
3061  * Otherwise do nothing.
3062  *
3063  * Returns: the possibly modified filename.
3064  */
3065 
gretl_maybe_prepend_dir(char * fname)3066 char *gretl_maybe_prepend_dir (char *fname)
3067 {
3068     char tmp[FILENAME_MAX];
3069 
3070     *tmp = '\0';
3071 
3072     if (fname[0] == '~' && fname[1] == '/') {
3073         char *home = getenv("HOME");
3074 
3075         if (home != NULL) {
3076             gretl_build_path(tmp, home, fname + 2, NULL);
3077         }
3078     } else if (!g_path_is_absolute(fname)) {
3079         gretl_build_path(tmp, paths.workdir, fname, NULL);
3080     }
3081 
3082     if (*tmp != '\0') {
3083         strcpy(fname, tmp);
3084     }
3085 
3086     return fname;
3087 }
3088 
3089 /**
3090  * gretl_read_user_file:
3091  * @fname: name of file to open.
3092  *
3093  * Attempts to open @fname in read-only mode.  If the file
3094  * is not found when the name is used "as is", we use
3095  * gretl_maybe_prepend_dir() to prepend the user's gretl
3096  * working directory and try again.
3097  *
3098  * Returns: file pointer, or NULL on failure.
3099  */
3100 
gretl_read_user_file(const char * fname)3101 FILE *gretl_read_user_file (const char *fname)
3102 {
3103     FILE *fp = gretl_fopen(fname, "r");
3104 
3105     if (fp == NULL) {
3106         char fullname[FILENAME_MAX];
3107 
3108         strcpy(fullname, fname);
3109         gretl_maybe_prepend_dir(fullname);
3110         if (*fullname != '\0') {
3111             fp = gretl_fopen(fullname, "r");
3112         }
3113     }
3114 
3115     return fp;
3116 }
3117 
3118 /* remove '.' and '..' from @path */
3119 
gretl_normalize_path(char * path)3120 int gretl_normalize_path (char *path)
3121 {
3122     char tmp[FILENAME_MAX];
3123     char split[3] = "/";
3124     char slash[2] = "/";
3125     char *pcpy, *pbit, *s = path;
3126     char **S, **P = NULL;
3127 #ifdef WIN32
3128     int fs = 0, bs = 0;
3129 #endif
3130     int i, n;
3131     int err = 0;
3132 
3133     if (*path == '\0') {
3134         return 0;
3135     }
3136 
3137 #ifdef WIN32
3138     while (*s) {
3139         if (*s == '\\') bs++;
3140         else if (*s == '/') fs++;
3141         s++;
3142     }
3143     if (fs > 0 && bs > 0) {
3144         strcpy(split, "\\/");
3145         strcpy(slash, "/");
3146     } else if (bs > 0) {
3147         strcpy(split, "\\");
3148         strcpy(slash, "\\");
3149     } else if (fs == 0) {
3150         return 0;
3151     }
3152 #else
3153     if (strstr(path, slash) == NULL) {
3154         return 0;
3155     }
3156 #endif
3157 
3158     if (*path == '.') {
3159         /* absolutize the path first, if necessary */
3160         gchar *cwd = g_get_current_dir();
3161 
3162         if (cwd != NULL) {
3163             char *tmp = gretl_strdup(path + 1);
3164 
3165             gretl_build_path(path, cwd, tmp, NULL);
3166             free(tmp);
3167             g_free(cwd);
3168         }
3169     }
3170 
3171     pcpy = gretl_strdup(path);
3172     if (pcpy == NULL) {
3173         return E_ALLOC;
3174     }
3175 
3176     *tmp = '\0';
3177     s = pcpy;
3178 
3179 #ifdef WIN32
3180     /* may be ok for a filename to start with a double backslash */
3181     if (!strncmp(path, "\\\\", 2)) {
3182         strcpy(tmp, slash);
3183         s++;
3184     } else if (*path && path[1] == ':') {
3185         strncat(tmp, path, 2);
3186         s += 2;
3187     }
3188 #endif
3189 
3190     /* split string @s on the path separator and cumulate
3191        the pieces in array P, skipping any pieces which
3192        are just "." */
3193 
3194     n = 0;
3195     while ((pbit = strtok(s, split)) != NULL && !err) {
3196         if (strcmp(pbit, ".")) {
3197             S = realloc(P, (n+1) * sizeof *P);
3198             if (S == NULL) {
3199                 err = E_ALLOC;
3200             } else {
3201                 P = S;
3202                 P[n++] = pbit;
3203             }
3204         }
3205         s = NULL; /* for subsequent strtok calls */
3206     }
3207 
3208     if (!err) {
3209         int j;
3210 
3211         /* let each ".." annihilate the preceding path chunk */
3212         for (i=n-1; i>0; i--) {
3213             if (P[i] != NULL && !strcmp(P[i], "..")) {
3214                 for (j=i-1; j>0; j--) {
3215                     if (P[j] != NULL && strcmp(P[j], "..")) {
3216                         P[j] = NULL;
3217                         break;
3218                     }
3219                 }
3220             }
3221         }
3222         /* re-assemble the path */
3223         for (i=0; i<n; i++) {
3224             if (P[i] != NULL && strcmp(P[i], "..")) {
3225                 strcat(tmp, slash);
3226                 strcat(tmp, P[i]);
3227             }
3228         }
3229         strcpy(path, tmp);
3230     }
3231 
3232     free(P);
3233     free(pcpy);
3234 
3235     return err;
3236 }
3237 
3238 /**
3239  * slash_terminate:
3240  * @path: path string.
3241  *
3242  * Check whether @path is already slash-terminated, and if
3243  * not, append a #SLASH; @path should be a large enough
3244  * array to accept an extra byte.
3245  *
3246  * Returns: 1 if a slash was appended, otherwise 0.
3247  */
3248 
slash_terminate(char * path)3249 int slash_terminate (char *path)
3250 {
3251 #ifdef WIN32
3252     if (path != NULL && *path != '\0') {
3253         int n = strlen(path);
3254 
3255         if (path[n-1] != '\\' && path[n-1] != '/') {
3256             char sep = getsep(path);
3257 
3258             strcat(path, sep == '/' ? "/" : "\\");
3259             return 1;
3260         }
3261     }
3262 #else
3263     if (path != NULL && *path != '\0') {
3264         if (path[strlen(path) - 1] != '/') {
3265             strcat(path, "/");
3266             return 1;
3267         }
3268     }
3269 #endif
3270 
3271     return 0;
3272 }
3273 
rc_set_gp_extra_colors(const char * s)3274 static void rc_set_gp_extra_colors (const char *s)
3275 {
3276     char cstr[2][8];
3277 
3278     *cstr[0] = *cstr[1] = '\0';
3279 
3280     if (sscanf(s, "%7s %7s", cstr[0], cstr[1]) == 2) {
3281         set_graph_color_from_string(0, cstr[0]);
3282         set_graph_color_from_string(1, cstr[1]);
3283     }
3284 }
3285 
rc_bool(const char * s)3286 static int rc_bool (const char *s)
3287 {
3288     if (!strcmp(s, "true") || !strcmp(s, "1")) {
3289         return 1;
3290     } else {
3291         return 0;
3292     }
3293 }
3294 
handle_use_cwd(int use_cwd,ConfigPaths * cpaths)3295 static void handle_use_cwd (int use_cwd, ConfigPaths *cpaths)
3296 {
3297     libset_set_bool(USE_CWD, use_cwd);
3298 
3299     if (use_cwd) {
3300         gchar *cwd = g_get_current_dir();
3301 
3302         if (cwd != NULL) {
3303             *cpaths->workdir = '\0';
3304             strncat(cpaths->workdir, cwd, MAXLEN - 2);
3305             slash_terminate(cpaths->workdir);
3306             g_free(cwd);
3307         }
3308     }
3309 }
3310 
3311 #define PROXLEN 64
3312 #define GRETLCLI_USE_CWD 1
3313 
3314 /* called only on behalf of gretlcli (for all platforms) */
3315 
get_gretl_config_from_file(FILE * fp,ConfigPaths * cpaths,char * dbproxy,int * use_proxy,int * updated,gchar ** gptheme)3316 void get_gretl_config_from_file (FILE *fp, ConfigPaths *cpaths,
3317                                  char *dbproxy, int *use_proxy,
3318                                  int *updated, gchar **gptheme)
3319 {
3320     char line[MAXLEN], key[32], val[MAXLEN];
3321 
3322     while (fgets(line, sizeof line, fp) != NULL) {
3323         if (*line == '#') {
3324             continue;
3325         }
3326         if (!strncmp(line, "recent", 6)) {
3327             /* reached the "recent files" section */
3328             break;
3329         }
3330         if (sscanf(line, "%s", key) != 1) {
3331             continue;
3332         }
3333         *val = '\0';
3334         /* get the string that follows " = " */
3335         strncat(val, line + strlen(key) + 3, MAXLEN - 1);
3336         gretl_strstrip(val);
3337         if (!strcmp(key, "gretldir")) {
3338             strncat(cpaths->gretldir, val, MAXLEN - 1);
3339 #ifndef WIN32
3340         } else if (!strcmp(key, "gnuplot")) {
3341             strncat(cpaths->gnuplot, val, MAXLEN - 1);
3342 #endif
3343         } else if (!strcmp(key, "workdir") || !strcmp(key, "userdir")) {
3344             /* "userdir" is a legacy thing */
3345             strncat(cpaths->workdir, val, MAXLEN - 1);
3346         } else if (!strcmp(key, "no_dotdir")) {
3347             cpaths->no_dotdir = rc_bool(val);
3348         } else if (!strcmp(key, "shellok")) {
3349             libset_set_bool(SHELL_OK, rc_bool(val));
3350         } else if (!strcmp(key, "usecwd")) {
3351 #if GRETLCLI_USE_CWD
3352             ; /* handled later */
3353 #else
3354             handle_use_cwd(rc_bool(val), cpaths);
3355 #endif
3356         } else if (!strcmp(key, "lcnumeric")) {
3357 	    set_lcnumeric(LANG_AUTO, rc_bool(val));
3358         } else if (!strcmp(key, "dbproxy")) {
3359             strncat(dbproxy, val, PROXLEN - 1);
3360         } else if (!strcmp(key, "useproxy")) {
3361             *use_proxy = rc_bool(val);
3362         } else if (!strcmp(key, "x12a")) {
3363             strncat(cpaths->x12a, val, MAXLEN - 1);
3364         } else if (!strcmp(key, "tramo")) {
3365             strncat(cpaths->tramo, val, MAXLEN - 1);
3366         } else if (!strcmp(key, "Rbin")) {
3367             strncat(cpaths->rbinpath, val, MAXLEN - 1);
3368         } else if (!strcmp(key, "Rlib")) {
3369             strncat(cpaths->rlibpath, val, MAXLEN - 1);
3370         } else if (!strcmp(key, "ox")) {
3371             strncat(cpaths->oxlpath, val, MAXLEN - 1);
3372         } else if (!strcmp(key, "octave")) {
3373             strncat(cpaths->octpath, val, MAXLEN - 1);
3374         } else if (!strcmp(key, "stata")) {
3375             strncat(cpaths->statapath, val, MAXLEN - 1);
3376         } else if (!strcmp(key, "python")) {
3377             strncat(cpaths->pypath, val, MAXLEN - 1);
3378         } else if (!strcmp(key, "julia")) {
3379             strncat(cpaths->jlpath, val, MAXLEN - 1);
3380 	} else if (!strcmp(key, "lpsolve")) {
3381 	    strncat(cpaths->lppath, val, MAXLEN - 1);
3382         } else if (!strcmp(key, "mpiexec")) {
3383             strncat(cpaths->mpiexec, val, MAXLEN - 1);
3384         } else if (!strcmp(key, "mpi_hosts")) {
3385             strncat(cpaths->mpi_hosts, val, MAXLEN - 1);
3386         } else if (!strcmp(key, "mpi_pref")) {
3387 #ifdef HAVE_MPI
3388             set_mpi_variant(val);
3389 #else
3390             ;
3391 #endif
3392         } else if (!strcmp(key, "Png_font")) {
3393             strncat(cpaths->pngfont, val, 128 - 1);
3394         } else if (!strcmp(key, "Gp_extra_colors")) {
3395             rc_set_gp_extra_colors(val);
3396         } else if (!strcmp(key, "HC_xsect")) {
3397             set_xsect_hccme(val);
3398         } else if (!strcmp(key, "HC_tseri")) {
3399             set_tseries_hccme(val);
3400         } else if (!strcmp(key, "HC_panel")) {
3401             set_panel_hccme(val);
3402         } else if (!strcmp(key, "HC_garch")) {
3403             set_garch_alt_vcv(val);
3404         } else if (!strcmp(key, "graph_theme")) {
3405             *gptheme = g_strdup(val);
3406         } else if (!strcmp(key, "build_date")) {
3407             *updated = gretl_is_updated(val);
3408         }
3409     }
3410 
3411 #if GRETLCLI_USE_CWD
3412     /* "workdir" is always the current directory */
3413     handle_use_cwd(1, cpaths);
3414 #endif
3415 }
3416 
3417 #ifndef WIN32
3418 
get_gretl_rc_path(char * rcfile)3419 void get_gretl_rc_path (char *rcfile)
3420 {
3421     char *path = getenv("GRETL_CONFIG_FILE");
3422 
3423     if (path != NULL) {
3424         *rcfile = '\0';
3425         strncat(rcfile, path, FILENAME_MAX - 1);
3426 #if 0
3427         fprintf(stderr, "rcfile from env: '%s'\n", rcfile);
3428 #endif
3429     } else {
3430         path = getenv("HOME");
3431         if (path != NULL) {
3432             sprintf(rcfile, "%s/.gretl2rc", path);
3433         } else {
3434             strcpy(rcfile, ".gretl2rc");
3435         }
3436     }
3437 }
3438 
3439 /* non-Windows read of the gretl configuration file on behalf
3440    of the CLI program, gretlcli; the Windows variant of this,
3441    win32_cli_read_rc(), is in gretl_win32.c
3442 */
3443 
cli_read_rc(void)3444 int cli_read_rc (void)
3445 {
3446     ConfigPaths cpaths = {0};
3447     char rcfile[FILENAME_MAX];
3448     char dbproxy[PROXLEN] = {0};
3449     gchar *gptheme = NULL;
3450     int use_proxy = 0;
3451     int updated = 0;
3452     FILE *fp;
3453     int err = 0;
3454 
3455     get_gretl_rc_path(rcfile);
3456     fp = gretl_fopen(rcfile, "r");
3457 
3458     if (fp == NULL) {
3459         err = E_FOPEN;
3460     } else {
3461         get_gretl_config_from_file(fp, &cpaths, dbproxy,
3462                                    &use_proxy, &updated,
3463                                    &gptheme);
3464         fclose(fp);
3465     }
3466 
3467     if (err) {
3468         gretl_set_paths(&cpaths);
3469     } else {
3470         err = gretl_set_paths(&cpaths);
3471     }
3472 
3473     if (gptheme != NULL) {
3474         set_plotstyle(gptheme);
3475         g_free(gptheme);
3476     }
3477 
3478     if (updated) {
3479         update_addons_index(NULL);
3480     }
3481 
3482 #ifdef USE_CURL
3483     gretl_www_init(dbproxy, use_proxy);
3484 #endif
3485 
3486 #if 0
3487     show_paths();
3488 #endif
3489 
3490     return err;
3491 }
3492 
3493 #endif /* !WIN32 */
3494 
3495 #ifdef OS_OSX
3496 
gretl_app_support_dir(void)3497 const char *gretl_app_support_dir (void)
3498 {
3499     static char suppdir[FILENAME_MAX];
3500 
3501     if (*suppdir == '\0') {
3502         /* try to ensure that we have a per-user Application
3503            Support dir, with appropriate subdirectories
3504         */
3505         const char *home = getenv("HOME");
3506 
3507         if (home == NULL) {
3508             fprintf(stderr, "problem: HOME is not defined\n");
3509         } else {
3510             char *p;
3511             int err;
3512 
3513             sprintf(suppdir, "%s/Library/Application Support/gretl/functions",
3514                     home);
3515             p = strrchr(suppdir, '/') + 1;
3516             err = gretl_mkdir(suppdir);
3517             if (!err) {
3518                 strcpy(p, "data");
3519                 err = gretl_mkdir(suppdir);
3520             }
3521             if (!err) {
3522                 strcpy(p, "db");
3523                 err = gretl_mkdir(suppdir);
3524             }
3525             if (err) {
3526                 *suppdir = '\0';
3527             } else {
3528                 /* chop off subdir from name */
3529                 *p = '\0';
3530             }
3531         }
3532     }
3533 
3534     return suppdir;
3535 }
3536 
3537 #endif
3538 
dir_is_writable(const char * dirname)3539 static int dir_is_writable (const char *dirname)
3540 {
3541     int ok = 0;
3542 
3543     if (gretl_mkdir(dirname) == 0) {
3544         gchar *test = g_strdup_printf("%s%c%s", dirname, SLASH, "wtest");
3545 
3546         if (test != NULL) {
3547             ok = (gretl_test_fopen(test, "w") == 0);
3548             g_free(test);
3549         }
3550     }
3551 
3552     return ok;
3553 }
3554 
get_user_install_path(char * path,const char * subdir)3555 static int get_user_install_path (char *path, const char *subdir)
3556 {
3557 #ifdef OS_OSX
3558     const char *dirname = gretl_app_support_dir();
3559 #else
3560     const char *dirname = gretl_dotdir();
3561 #endif
3562     int err = 0;
3563 
3564     if (dirname == NULL || *dirname == '\0') {
3565         err = E_FOPEN;
3566     } else {
3567         sprintf(path, "%s%s", dirname, subdir);
3568         err = (dir_is_writable(path) == 0);
3569     }
3570 
3571     return err;
3572 }
3573 
get_system_install_path(char * path,const char * subdir)3574 static int get_system_install_path (char *path, const char *subdir)
3575 {
3576     sprintf(path, "%s%s", gretl_home(), subdir);
3577 
3578     if (dir_is_writable(path)) {
3579         return 0;
3580     } else {
3581         return E_FOPEN;
3582     }
3583 }
3584 
3585 /* get a path that's suitable for writing a function
3586    package on installation
3587 */
3588 
gretl_function_package_path(void)3589 const char *gretl_function_package_path (void)
3590 {
3591     static char path[FILENAME_MAX];
3592 
3593     if (*path == '\0') {
3594         int sys_first = 1;
3595         int err = 0;
3596 
3597 #if defined(OS_OSX)
3598         /* we prefer writing to ~/Library/Application Support */
3599         sys_first = 0;
3600 #elif defined(WIN32)
3601         sys_first = 0;
3602 #endif
3603         if (sys_first) {
3604             err = get_system_install_path(path, "functions");
3605             if (err) {
3606                 err = get_user_install_path(path, "functions");
3607             }
3608         } else {
3609             err = get_user_install_path(path, "functions");
3610         }
3611 
3612         if (err) {
3613             *path = '\0';
3614         } else {
3615             slash_terminate(path);
3616         }
3617     }
3618 
3619     return path;
3620 }
3621 
gretl_path_compose(char * targ,int len,const char * s1,const char * s2)3622 int gretl_path_compose (char *targ, int len,
3623                         const char *s1,
3624                         const char *s2)
3625 {
3626     targ[0] = '\0';
3627     if (strlen(s1) + strlen(s2) >= len) {
3628         gretl_errmsg_set("filename is too long");
3629         return E_DATA;
3630     } else {
3631         strcpy(targ, s1);
3632         strcat(targ, s2);
3633         return 0;
3634     }
3635 }
3636 
3637 /* Code borrowed from GLib (gfileutils.c) and adapted to
3638    write to an input char * (@targ) instead of returning
3639    a newly allocated string. The code is also somewhat
3640    simplified by the assumption that if the platform is
3641    not MS Windows the directory separator is always '/':
3642    this is a safe assumption for the platforms supported
3643    by gretl.
3644 */
3645 
3646 #ifdef G_OS_WIN32
3647 
real_build_path_win32(char * targ,const gchar * first_element,va_list * args)3648 static void real_build_path_win32 (char *targ,
3649                                    const gchar *first_element,
3650                                    va_list *args)
3651 {
3652     gboolean is_first = TRUE;
3653     gboolean have_leading = FALSE;
3654     const gchar *single_element = NULL;
3655     const gchar *next_element;
3656     const gchar *last_trailing = NULL;
3657     gchar current_separator = '\\';
3658 
3659     next_element = first_element;
3660 
3661     while (1) {
3662         const gchar *element;
3663         const gchar *start;
3664         const gchar *end;
3665 
3666         if (next_element) {
3667             element = next_element;
3668             next_element = va_arg(*args, gchar *);
3669         } else {
3670             break;
3671         }
3672 
3673         /* ignore empty elements */
3674         if (*element == '\0') {
3675             continue;
3676         }
3677 
3678         start = element;
3679         while (start && (*start == '\\' || *start == '/')) {
3680             current_separator = *start;
3681             start++;
3682         }
3683 
3684         end = start + strlen(start);
3685         while (end >= start + 1 && (end[-1] == '\\' || end[-1] == '/')) {
3686             current_separator = end[-1];
3687             end--;
3688         }
3689 
3690         last_trailing = end;
3691         while (last_trailing >= element + 1 &&
3692                (last_trailing[-1] == '\\' || last_trailing[-1] == '/')) {
3693             last_trailing--;
3694         }
3695 
3696         if (!have_leading) {
3697             /* If the leading and trailing separator strings are in the
3698                same element and overlap, the result is exactly that
3699                element
3700             */
3701             if (last_trailing <= start) {
3702                 single_element = element;
3703             }
3704             strncat(targ, element, start - element);
3705             have_leading = TRUE;
3706         } else {
3707             single_element = NULL;
3708         }
3709 
3710         if (end == start) {
3711             continue;
3712         }
3713 
3714         if (!is_first) {
3715             strncat(targ, &current_separator, 1);
3716         }
3717         strncat(targ, start, end - start);
3718         is_first = FALSE;
3719     }
3720 
3721     if (single_element) {
3722         *targ = '\0';
3723         strcat(targ, single_element);
3724     } else if (last_trailing) {
3725         strcat(targ, last_trailing);
3726     }
3727 }
3728 
3729 #else
3730 
real_build_path(char * targ,const gchar * first_element,va_list * args)3731 static void real_build_path (char *targ,
3732                              const gchar *first_element,
3733                              va_list *args)
3734 {
3735     gboolean is_first = TRUE;
3736     gboolean have_leading = FALSE;
3737     const gchar *single_element = NULL;
3738     const gchar *next_element;
3739     const gchar *last_trailing = NULL;
3740 
3741     next_element = first_element;
3742 
3743     while (1) {
3744         const gchar *element;
3745         const gchar *start;
3746         const gchar *end;
3747 
3748         if (next_element) {
3749             element = next_element;
3750             next_element = va_arg(*args, gchar *);
3751         } else {
3752             break;
3753         }
3754 
3755         /* ignore empty elements */
3756         if (*element == '\0') {
3757             continue;
3758         }
3759 
3760         start = element;
3761         while (*start == '/') {
3762             start++;
3763         }
3764 
3765         end = start + strlen (start);
3766         while (end >= start + 1 && end[-1] == '/') {
3767             end--;
3768         }
3769 
3770         last_trailing = end;
3771         while (last_trailing >= element + 1 && last_trailing[-1] == '/') {
3772             last_trailing--;
3773         }
3774 
3775         if (!have_leading) {
3776             /* If the leading and trailing separator strings are in the
3777                same element and overlap, the result is exactly that
3778                element
3779             */
3780             if (last_trailing <= start) {
3781                 single_element = element;
3782             }
3783             strncat(targ, element, start - element);
3784             have_leading = TRUE;
3785         } else {
3786             single_element = NULL;
3787         }
3788 
3789         if (end == start) {
3790             continue;
3791         }
3792 
3793         if (!is_first) {
3794             strcat(targ, "/");
3795         }
3796         strncat(targ, start, end - start);
3797         is_first = FALSE;
3798     }
3799 
3800     if (single_element) {
3801         *targ = '\0';
3802         strcat(targ, single_element);
3803     } else if (last_trailing) {
3804         strcat(targ, last_trailing);
3805     }
3806 }
3807 
3808 #endif
3809 
3810 /**
3811  * gretl_build_path:
3812  * @targ: target string to write to (must be pre-allocated).
3813  * @first_element: first component of path.
3814  *
3815  * Writes to @targ a path composed of @first_element
3816  * plus any additional string arguments supplied before
3817  * a terminating NULL. An appropriate separator is inserted
3818  * between the components of the path.
3819  *
3820  * Returns: the target string, @targ.
3821  */
3822 
gretl_build_path(char * targ,const gchar * first_element,...)3823 char *gretl_build_path (char *targ, const gchar *first_element, ...)
3824 {
3825     va_list args;
3826 
3827     *targ = '\0';
3828 
3829     va_start(args, first_element);
3830 #ifdef G_OS_WIN32
3831     real_build_path_win32(targ, first_element, &args);
3832 #else
3833     real_build_path(targ, first_element, &args);
3834 #endif
3835     va_end(args);
3836 
3837     return targ;
3838 }
3839 
3840 struct foreign_paths {
3841     const char *id;
3842     const char *path;
3843 };
3844 
3845 static struct foreign_paths fpaths[] = {
3846     { "Rbin",    paths.rbinpath },
3847     { "Rlib",    paths.rlibpath },
3848     { "ox",      paths.oxlpath },
3849     { "octave",  paths.octpath },
3850     { "stata",   paths.statapath },
3851     { "python",  paths.pypath },
3852     { "julia",   paths.jlpath },
3853     { "lpsolve", paths.lppath },
3854     { NULL, NULL}
3855 };
3856 
foreign_info(void)3857 gretl_bundle *foreign_info (void)
3858 {
3859     gretl_bundle *b = gretl_bundle_new();
3860     gchar *fullpath;
3861     int found, i;
3862 
3863     for (i=0; fpaths[i].id != NULL; i++) {
3864 	if (fpaths[i].path[0] == '\0') {
3865 	    gretl_bundle_set_int(b, fpaths[i].id, 0);
3866 	} else if (g_path_is_absolute(fpaths[i].path)) {
3867 	    found = gretl_stat(fpaths[i].path, NULL) == 0;
3868 	    gretl_bundle_set_int(b, fpaths[i].id, found);
3869 	} else {
3870 	    fullpath = g_find_program_in_path(fpaths[i].path);
3871 	    if (fullpath == NULL) {
3872 		gretl_bundle_set_int(b, fpaths[i].id, 0);
3873 	    } else {
3874 		gretl_bundle_set_int(b, fpaths[i].id, 1);
3875 		g_free(fullpath);
3876 	    }
3877 	}
3878     }
3879 
3880     return b;
3881 }
3882