Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / variable.c
diff --git a/src/variable.c b/src/variable.c
new file mode 100644 (file)
index 0000000..62cc8dd
--- /dev/null
@@ -0,0 +1,600 @@
+#ifndef lint
+static char *RCSid() { return RCSid("$Id: variable.c,v 1.27.2.1 2008/12/12 07:14:11 sfeam Exp $"); }
+#endif
+
+/* GNUPLOT - variable.c */
+
+/*[
+ * Copyright 1999, 2004   Lars Hecking
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code.  Modifications are to
+ * be distributed as patches to the released version.  Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ *   1. distribute the corresponding source modifications from the
+ *    released version in the form of a patch file along with the binaries,
+ *   2. add special version identification to distinguish your version
+ *    in addition to the base release version number,
+ *   3. provide your name and address as the primary contact for the
+ *    support of your modified version, and
+ *   4. retain our contact information in regard to use of the base
+ *    software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+/* The Death of Global Variables - part one. */
+
+#include <string.h>
+
+#include "variable.h"
+
+#include "alloc.h"
+#include "command.h"
+#include "util.h"
+
+
+#define PATHSEP_TO_NUL(arg)                    \
+do {                                           \
+    char *s = arg;                             \
+    while ((s = strchr(s, PATHSEP)) != NULL)   \
+       *s++ = NUL;                             \
+} while (0)
+
+#define PRINT_PATHLIST(start, limit)           \
+do {                                           \
+    char *s = start;                           \
+                                               \
+    while (s < limit) {                                \
+       fprintf(stderr, "\"%s\" ", s);          \
+       s += strlen(s) + 1;                     \
+    }                                          \
+    fputc('\n',stderr);                                \
+} while (0)
+
+/*
+ * char *loadpath_handler (int, char *)
+ *
+ */
+char *
+loadpath_handler(int action, char *path)
+{
+    /* loadpath variable
+     * the path elements are '\0' separated (!)
+     * this way, reading out loadpath is very
+     * easy to implement */
+    static char *loadpath;
+    /* index pointer, end of loadpath,
+     * env section of loadpath, current limit, in that order */
+    static char *p, *last, *envptr, *limit;
+
+    switch (action) {
+    case ACTION_CLEAR:
+       /* Clear loadpath, fall through to init */
+       FPRINTF((stderr, "Clear loadpath\n"));
+       free(loadpath);
+       loadpath = p = last = NULL;
+       /* HBB 20000726: 'limit' has to be initialized to NULL, too! */
+       limit = NULL;
+    case ACTION_INIT:
+       /* Init loadpath from environment */
+       FPRINTF((stderr, "Init loadpath from environment\n"));
+       assert(loadpath == NULL);
+       if (!loadpath)
+       {
+           char *envlib = getenv("GNUPLOT_LIB");
+           if (envlib) {
+               int len = strlen(envlib);
+               loadpath = gp_strdup(envlib);
+               /* point to end of loadpath */
+               last = loadpath + len;
+               /* convert all PATHSEPs to \0 */
+               PATHSEP_TO_NUL(loadpath);
+           }                   /* else: NULL = empty */
+       }                       /* else: already initialised; int_warn (?) */
+       /* point to env portion of loadpath */
+       envptr = loadpath;
+       break;
+    case ACTION_SET:
+       /* set the loadpath */
+       FPRINTF((stderr, "Set loadpath\n"));
+       if (path && *path != NUL) {
+           /* length of env portion */
+           size_t elen = last - envptr;
+           size_t plen = strlen(path);
+           if (loadpath && envptr) {
+               /* we are prepending a path name; because
+                * realloc() preserves only the contents up
+                * to the minimum of old and new size, we move
+                * the part to be preserved to the beginning
+                * of the string; use memmove() because strings
+                * may overlap */
+               memmove(loadpath, envptr, elen + 1);
+           }
+           loadpath = gp_realloc(loadpath, elen + 1 + plen + 1, "expand loadpath");
+           /* now move env part back to the end to make space for
+            * the new path */
+           memmove(loadpath + plen + 1, loadpath, elen + 1);
+           strcpy(loadpath, path);
+           /* separate new path(s) and env path(s) */
+           loadpath[plen] = PATHSEP;
+           /* adjust pointer to env part and last */
+           envptr = &loadpath[plen+1];
+           last = envptr + elen;
+           PATHSEP_TO_NUL(loadpath);
+       }                       /* else: NULL = empty */
+       break;
+    case ACTION_SHOW:
+       /* print the current, full loadpath */
+       FPRINTF((stderr, "Show loadpath\n"));
+       if (loadpath) {
+           fputs("\tloadpath is ", stderr);
+           PRINT_PATHLIST(loadpath, envptr);
+           if (envptr) {
+               /* env part */
+               fputs("\tsystem loadpath is ", stderr);
+               PRINT_PATHLIST(envptr, last);
+           }
+       } else
+           fputs("\tloadpath is empty\n", stderr);
+       break;
+    case ACTION_SAVE:
+       /* we don't save the load path taken from the
+        * environment, so don't go beyond envptr when
+        * extracting the path elements
+        */
+       limit = envptr;
+    case ACTION_GET:
+       /* subsequent calls to get_loadpath() return all
+        * elements of the loadpath until exhausted
+        */
+       FPRINTF((stderr, "Get loadpath\n"));
+       if (!loadpath)
+           return NULL;
+       if (!p) {
+           /* init section */
+           p = loadpath;
+           if (!limit)
+               limit = last;
+       } else {
+           /* skip over '\0' */
+           p += strlen(p) + 1;
+       }
+       if (p >= limit) 
+           limit = p = NULL;
+       return p;
+       break;
+    case ACTION_NULL:
+       /* just return */
+    default:
+       break;
+    }
+
+    /* should always be ignored - points to the
+     * first path in the list */
+    return loadpath;
+
+}
+
+
+
+struct path_table {
+    const char *dir;
+};
+
+/* Yet, no special font paths for these operating systems:
+ * MSDOS, ATARI, AMIGA, MTOS, NeXT, ultrix, VMS, _IBMR2, alliant
+ *
+ * Environmental variables are written as $(name).
+ * Commands are written as $`command`.
+ */
+
+#if defined(OS2) && !defined(FONTPATHSET)
+#  define FONTPATHSET
+static const struct path_table fontpath_tbl[] =
+{
+    { "$(BOOTDIR)/PSFONTS" },
+    /* X11 */
+    { "$(X11ROOT)/X11R6/lib/X11/fonts/Type1" },
+    { NULL }
+};
+#endif
+
+#if defined(_Windows) && !defined(FONTPATHSET)
+#  define FONTPATHSET
+static const struct path_table fontpath_tbl[] =
+{
+    { "$(windir)\\fonts" },
+    /* Ghostscript */
+    { "c:\\gs\\fonts" },
+    /* X11 */
+    { "$(CYGWIN_ROOT)\\usr\\X11R6\\lib\\X11\\fonts\\Type1" },
+#ifdef HAVE_KPSEXPAND
+    /* fpTeX */
+    { "$`kpsewhich -expand-path=$HOMETEXMF`\\fonts\\type1!" },
+    { "$`kpsewhich -expand-path=$TEXMFLOCAL`\\fonts\\type1!" },
+    { "$`kpsewhich -expand-path=$TEXMFMAIN`\\fonts\\type1!" },
+    { "$`kpsewhich -expand-path=$TEXMFDIST`\\fonts\\type1!" },
+#endif
+    { NULL }
+};
+#endif
+
+#if defined(_Macintosh) && !defined(FONTPATHSET)
+#  define FONTPATHSET
+static const struct path_table fontpath_tbl[] =
+{
+    { "/System/Library/Fonts!" },
+    { "/Library/Fonts!" },
+    { "$(HOME)/Library/Fonts!" },
+    { NULL }
+};
+#endif
+
+#if defined(VMS) && !defined(FONTPATHSET)
+#  define FONTPATHSET
+static const struct path_table fontpath_tbl[] =
+{
+    { "SYS$COMMON:[SYSFONT]!" },
+    { NULL }
+};
+#endif
+
+/* Fallback: Should work for unix */
+#ifndef FONTPATHSET
+static const struct path_table fontpath_tbl[] =
+{
+#ifdef HAVE_KPSEXPAND
+    /* teTeX or TeXLive */
+    { "$`kpsexpand '$HOMETEXMF'`/fonts/type1!" },
+    { "$`kpsexpand '$TEXMFLOCAL'`/fonts/type1!" },
+    { "$`kpsexpand '$TEXMFMAIN'`/fonts/type1!" },
+    { "$`kpsexpand '$TEXMFDIST'`/fonts/type1!" },
+#endif
+    /* Linux paths */
+    { "/usr/X11R6/lib/X11/fonts/Type1" },
+    { "/usr/X11R6/lib/X11/fonts/truetype" },
+    /* HP-UX */
+    { "/usr/lib/X11/fonts!"},
+    /* Ghostscript */
+    { "/usr/share/ghostscript/fonts" },
+    { "/usr/local/share/ghostscript/fonts" },
+    { NULL }
+};
+#endif
+
+#undef FONTPATHSET
+
+static TBOOLEAN fontpath_init_done = FALSE;
+
+/*
+ * char *fontpath_handler (int, char *)
+ *
+ */
+char *
+fontpath_handler(int action, char *path)
+{
+    /* fontpath variable
+     * the path elements are '\0' separated (!)
+     * this way, reading out fontpath is very
+     * easy to implement */
+    static char *fontpath;
+    /* index pointer, end of fontpath,
+     * env section of fontpath, current limit, in that order */
+    static char *p, *last, *envptr, *limit;
+
+    if (!fontpath_init_done) {
+       fontpath_init_done = TRUE;
+       init_fontpath();
+    }
+
+    switch (action) {
+    case ACTION_CLEAR:
+       /* Clear fontpath, fall through to init */
+       FPRINTF((stderr, "Clear fontpath\n"));
+       free(fontpath);
+       fontpath = p = last = NULL;
+       /* HBB 20000726: 'limit' has to be initialized to NULL, too! */
+       limit = NULL;
+    case ACTION_INIT:
+       /* Init fontpath from environment */
+       FPRINTF((stderr, "Init fontpath from environment\n"));
+       assert(fontpath == NULL);
+       if (!fontpath)
+       {
+           char *envlib = getenv("GNUPLOT_FONTPATH");
+           if (envlib) {
+               /* get paths from environment */
+               int len = strlen(envlib);
+               fontpath = gp_strdup(envlib);
+               /* point to end of fontpath */
+               last = fontpath + len;
+               /* convert all PATHSEPs to \0 */
+               PATHSEP_TO_NUL(fontpath);
+           }
+#if defined(HAVE_DIRENT_H) || defined(_Windows)
+           else {
+               /* set hardcoded paths */
+               const struct path_table *curr_fontpath = fontpath_tbl;
+
+               while (curr_fontpath->dir) {
+                   char *currdir = NULL;
+                   char *envbeg = NULL;
+#  if defined(PIPES)
+                   char *cmdbeg = NULL;
+#  endif
+                   TBOOLEAN subdirs = FALSE;
+
+                   currdir = gp_strdup( curr_fontpath->dir );
+
+                   while ( (envbeg=strstr(currdir, "$("))
+#  if defined(PIPES)
+                           || (cmdbeg=strstr( currdir, "$`" ))
+#  endif
+                           ) {
+                       /* Read environment variables */
+                       if (envbeg) {
+                           char *tmpdir = NULL;
+                           char *envend = NULL, *envval = NULL;
+                           unsigned int envlen;
+                           envend = strchr(envbeg+2,')');
+                           envend[0] = '\0';
+                           envval = getenv(envbeg+2);
+                           envend[0] = ')';
+                           envlen = envval ? strlen(envval) : 0;
+                           tmpdir = gp_alloc(strlen(currdir)+envlen
+                                             +envbeg-envend+1,
+                                             "expand fontpath");
+                           strncpy(tmpdir,currdir,envbeg-currdir);
+                           if (envval)
+                               strcpy(tmpdir+(envbeg-currdir),envval);
+                           strcpy(tmpdir+(envbeg-currdir+envlen), envend+1);
+
+                           free(currdir);
+                           currdir = tmpdir;
+                       }
+#  if defined(PIPES)
+                       /* Read environment variables */
+                       else if (cmdbeg) {
+                           char *tmpdir = NULL;
+                           char *envend = NULL;
+                           char envval[256];
+                           unsigned int envlen;
+                           FILE *fcmd;
+                           envend = strchr(cmdbeg+2,'`');
+                           envend[0] = '\0';
+                           fcmd = popen(cmdbeg+2,"r");
+                           if (fcmd) {
+                               fgets(envval,255,fcmd);
+                               if (envval[strlen(envval)-1]=='\n')
+                                   envval[strlen(envval)-1]='\0';
+                               pclose(fcmd);
+                           }
+                           envend[0] = '`';
+                           envlen = strlen(envval);
+                           tmpdir = gp_alloc(strlen(currdir)+envlen
+                                             +cmdbeg-envend+1,
+                                             "expand fontpath");
+                           strncpy(tmpdir,currdir,cmdbeg-currdir);
+                           strcpy(tmpdir+(cmdbeg-currdir),envval);
+                           strcpy(tmpdir+(cmdbeg-currdir+envlen), envend+1);
+
+                           free(currdir);
+                           currdir = tmpdir;
+                       }
+#  endif
+                   }
+
+                   if ( currdir[strlen(currdir)-1] == '!' ) {
+                       /* search subdirectories */
+                       /* delete ! from directory name */
+                       currdir[strlen(currdir)-1] = '\0';
+                       subdirs = TRUE;
+                   }
+
+                   if ( existdir( currdir ) ) {
+                       size_t plen;
+                       if ( subdirs )
+                           /* add ! to directory name again */
+                           currdir[strlen(currdir)] = '!';
+                       plen = strlen(currdir);
+                       if (fontpath) {
+                           size_t elen = strlen(fontpath);
+                           fontpath = gp_realloc(fontpath,
+                                                 elen + 1 + plen + 1,
+                                                 "expand fontpath");
+                           last = fontpath+elen;
+                           *last = PATHSEP;
+                           ++last;
+                           *last = '\0';
+                       } else {
+                           fontpath = gp_alloc(plen + 1,
+                                               "expand fontpath");
+                           last = fontpath;
+                       }
+
+                       strcpy(last, currdir );
+                       last += plen;
+                   }
+                   curr_fontpath++;
+                   if (currdir) {
+                       free(currdir);
+                       currdir = NULL;
+                   }
+               }
+               /* convert all PATHSEPs to \0 */
+               if (fontpath)
+                   PATHSEP_TO_NUL(fontpath);
+           }
+#endif /* HAVE_DIRENT_H */
+
+       }                       /* else: already initialised; int_warn (?) */
+       /* point to env portion of fontpath */
+       envptr = fontpath;
+       break;
+    case ACTION_SET:
+       /* set the fontpath */
+       FPRINTF((stderr, "Set fontpath\n"));
+       if (path && *path != NUL) {
+           /* length of env portion */
+           size_t elen = last - envptr;
+           size_t plen = strlen(path);
+           if (fontpath && envptr) {
+               /* we are prepending a path name; because
+                * realloc() preserves only the contents up
+                * to the minimum of old and new size, we move
+                * the part to be preserved to the beginning
+                * of the string; use memmove() because strings
+                * may overlap */
+               memmove(fontpath, envptr, elen + 1);
+           }
+           fontpath = gp_realloc(fontpath, elen + 1 + plen + 1, "expand fontpath");
+           /* now move env part back to the end to make space for
+            * the new path */
+           memmove(fontpath + plen + 1, fontpath, elen + 1);
+           strcpy(fontpath, path);
+           /* separate new path(s) and env path(s) */
+           fontpath[plen] = PATHSEP;
+           /* adjust pointer to env part and last */
+           envptr = &fontpath[plen+1];
+           last = envptr + elen;
+           PATHSEP_TO_NUL(fontpath);
+       }                       /* else: NULL = empty */
+       break;
+    case ACTION_SHOW:
+       /* print the current, full fontpath */
+       FPRINTF((stderr, "Show fontpath\n"));
+       if (fontpath) {
+           fputs("\tfontpath is ", stderr);
+           PRINT_PATHLIST(fontpath, envptr);
+           if (envptr) {
+               /* env part */
+               fputs("\tsystem fontpath is ", stderr);
+               PRINT_PATHLIST(envptr, last);
+           }
+       } else
+           fputs("\tfontpath is empty\n", stderr);
+       break;
+    case ACTION_SAVE:
+       /* we don't save the font path taken from the
+        * environment, so don't go beyond envptr when
+        * extracting the path elements
+        */
+       limit = envptr;
+    case ACTION_GET:
+       /* subsequent calls to get_fontpath() return all
+        * elements of the fontpath until exhausted
+        */
+       FPRINTF((stderr, "Get fontpath\n"));
+       if (!fontpath)
+           return NULL;
+       if (!p) {
+           /* init section */
+           p = fontpath;
+           if (!limit)
+               limit = last;
+       } else {
+           /* skip over '\0' */
+           p += strlen(p) + 1;
+       }
+       if (p >= limit)
+           limit = p = NULL;
+       return p;
+    case ACTION_NULL:
+       /* just return */
+    default:
+       break;
+    }
+
+    /* should always be ignored - points to the
+     * first path in the list */
+    return fontpath;
+
+}
+
+/* not set or shown directly, but controlled by 'set locale'
+ * defined in national.h
+ */
+
+char full_month_names[12][32] =
+{ FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
+char abbrev_month_names[12][8] =
+{ AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };
+
+char full_day_names[7][32] =
+{ FDAY0, FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6 };
+char abbrev_day_names[7][8] =
+{ ADAY0, ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6 };
+
+char *
+locale_handler(int action, char *newlocale)
+{
+    static char *current_locale = NULL;
+    struct tm tm;
+    int i;
+
+    switch(action) {
+    case ACTION_CLEAR:
+    case ACTION_INIT:
+       if (current_locale) free(current_locale);
+       current_locale = gp_strdup(INITIAL_LOCALE);
+       break;
+    case ACTION_SET:
+/* FIXME: configure test for setlocale() */
+#ifdef HAVE_LOCALE_H
+       if (setlocale(LC_TIME, newlocale)) {
+           current_locale = gp_realloc(current_locale, strlen(newlocale) + 1, "locale");
+           strcpy(current_locale, newlocale);
+       }
+       else
+           int_error(c_token, "Locale not available");
+
+       /* we can do a *lot* better than this ; eg use system functions
+        * where available; create values on first use, etc
+        */
+       memset(&tm, 0, sizeof(struct tm));
+       for (i = 0; i < 7; ++i) {
+           tm.tm_wday = i;             /* hope this enough */
+           strftime(full_day_names[i], sizeof(full_day_names[i]), "%A", &tm);
+           strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%a", &tm);
+       }
+       for (i = 0; i < 12; ++i) {
+           tm.tm_mon = i;              /* hope this enough */
+           strftime(full_month_names[i], sizeof(full_month_names[i]), "%B", &tm);
+           strftime(abbrev_month_names[i], sizeof(abbrev_month_names[i]), "%b", &tm);
+       }
+#else
+       current_locale = gp_realloc(current_locale, strlen(newlocale) + 1, "locale");
+       strcpy(current_locale, newlocale);
+#endif /* HAVE_LOCALE_H */
+       break;
+    case ACTION_SHOW:
+#ifdef HAVE_LOCALE_H
+       fprintf(stderr, "\tLC_CTYPE is %s\n", setlocale(LC_CTYPE,NULL));
+       fprintf(stderr, "\tLC_TIME is %s\n", setlocale(LC_TIME,NULL));
+#else
+       fprintf(stderr, "\tlocale is \"%s\"\n", current_locale);
+#endif
+       break;
+    case ACTION_SAVE:
+    case ACTION_GET:
+    case ACTION_NULL:
+    default:
+       /* just return */
+       break;
+    }
+
+    return current_locale;
+}
+