"Fossies" - the Fresh Open Source Software Archive

Member "gretl-2020e/lib/src/gretl_paths.c" (7 Nov 2020, 90039 Bytes) of package /linux/misc/gretl-2020e.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gretl_paths.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2020d_vs_2020e.

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