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, ¤t_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