Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / variable.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: variable.c,v 1.27.2.1 2008/12/12 07:14:11 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - variable.c */
6
7 /*[
8  * Copyright 1999, 2004   Lars Hecking
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /* The Death of Global Variables - part one. */
38
39 #include <string.h>
40
41 #include "variable.h"
42
43 #include "alloc.h"
44 #include "command.h"
45 #include "util.h"
46
47
48 #define PATHSEP_TO_NUL(arg)                     \
49 do {                                            \
50     char *s = arg;                              \
51     while ((s = strchr(s, PATHSEP)) != NULL)    \
52         *s++ = NUL;                             \
53 } while (0)
54
55 #define PRINT_PATHLIST(start, limit)            \
56 do {                                            \
57     char *s = start;                            \
58                                                 \
59     while (s < limit) {                         \
60         fprintf(stderr, "\"%s\" ", s);          \
61         s += strlen(s) + 1;                     \
62     }                                           \
63     fputc('\n',stderr);                         \
64 } while (0)
65
66 /*
67  * char *loadpath_handler (int, char *)
68  *
69  */
70 char *
71 loadpath_handler(int action, char *path)
72 {
73     /* loadpath variable
74      * the path elements are '\0' separated (!)
75      * this way, reading out loadpath is very
76      * easy to implement */
77     static char *loadpath;
78     /* index pointer, end of loadpath,
79      * env section of loadpath, current limit, in that order */
80     static char *p, *last, *envptr, *limit;
81
82     switch (action) {
83     case ACTION_CLEAR:
84         /* Clear loadpath, fall through to init */
85         FPRINTF((stderr, "Clear loadpath\n"));
86         free(loadpath);
87         loadpath = p = last = NULL;
88         /* HBB 20000726: 'limit' has to be initialized to NULL, too! */
89         limit = NULL;
90     case ACTION_INIT:
91         /* Init loadpath from environment */
92         FPRINTF((stderr, "Init loadpath from environment\n"));
93         assert(loadpath == NULL);
94         if (!loadpath)
95         {
96             char *envlib = getenv("GNUPLOT_LIB");
97             if (envlib) {
98                 int len = strlen(envlib);
99                 loadpath = gp_strdup(envlib);
100                 /* point to end of loadpath */
101                 last = loadpath + len;
102                 /* convert all PATHSEPs to \0 */
103                 PATHSEP_TO_NUL(loadpath);
104             }                   /* else: NULL = empty */
105         }                       /* else: already initialised; int_warn (?) */
106         /* point to env portion of loadpath */
107         envptr = loadpath;
108         break;
109     case ACTION_SET:
110         /* set the loadpath */
111         FPRINTF((stderr, "Set loadpath\n"));
112         if (path && *path != NUL) {
113             /* length of env portion */
114             size_t elen = last - envptr;
115             size_t plen = strlen(path);
116             if (loadpath && envptr) {
117                 /* we are prepending a path name; because
118                  * realloc() preserves only the contents up
119                  * to the minimum of old and new size, we move
120                  * the part to be preserved to the beginning
121                  * of the string; use memmove() because strings
122                  * may overlap */
123                 memmove(loadpath, envptr, elen + 1);
124             }
125             loadpath = gp_realloc(loadpath, elen + 1 + plen + 1, "expand loadpath");
126             /* now move env part back to the end to make space for
127              * the new path */
128             memmove(loadpath + plen + 1, loadpath, elen + 1);
129             strcpy(loadpath, path);
130             /* separate new path(s) and env path(s) */
131             loadpath[plen] = PATHSEP;
132             /* adjust pointer to env part and last */
133             envptr = &loadpath[plen+1];
134             last = envptr + elen;
135             PATHSEP_TO_NUL(loadpath);
136         }                       /* else: NULL = empty */
137         break;
138     case ACTION_SHOW:
139         /* print the current, full loadpath */
140         FPRINTF((stderr, "Show loadpath\n"));
141         if (loadpath) {
142             fputs("\tloadpath is ", stderr);
143             PRINT_PATHLIST(loadpath, envptr);
144             if (envptr) {
145                 /* env part */
146                 fputs("\tsystem loadpath is ", stderr);
147                 PRINT_PATHLIST(envptr, last);
148             }
149         } else
150             fputs("\tloadpath is empty\n", stderr);
151         break;
152     case ACTION_SAVE:
153         /* we don't save the load path taken from the
154          * environment, so don't go beyond envptr when
155          * extracting the path elements
156          */
157         limit = envptr;
158     case ACTION_GET:
159         /* subsequent calls to get_loadpath() return all
160          * elements of the loadpath until exhausted
161          */
162         FPRINTF((stderr, "Get loadpath\n"));
163         if (!loadpath)
164             return NULL;
165         if (!p) {
166             /* init section */
167             p = loadpath;
168             if (!limit)
169                 limit = last;
170         } else {
171             /* skip over '\0' */
172             p += strlen(p) + 1;
173         }
174         if (p >= limit) 
175             limit = p = NULL;
176         return p;
177         break;
178     case ACTION_NULL:
179         /* just return */
180     default:
181         break;
182     }
183
184     /* should always be ignored - points to the
185      * first path in the list */
186     return loadpath;
187
188 }
189
190
191
192 struct path_table {
193     const char *dir;
194 };
195
196 /* Yet, no special font paths for these operating systems:
197  * MSDOS, ATARI, AMIGA, MTOS, NeXT, ultrix, VMS, _IBMR2, alliant
198  *
199  * Environmental variables are written as $(name).
200  * Commands are written as $`command`.
201  */
202
203 #if defined(OS2) && !defined(FONTPATHSET)
204 #  define FONTPATHSET
205 static const struct path_table fontpath_tbl[] =
206 {
207     { "$(BOOTDIR)/PSFONTS" },
208     /* X11 */
209     { "$(X11ROOT)/X11R6/lib/X11/fonts/Type1" },
210     { NULL }
211 };
212 #endif
213
214 #if defined(_Windows) && !defined(FONTPATHSET)
215 #  define FONTPATHSET
216 static const struct path_table fontpath_tbl[] =
217 {
218     { "$(windir)\\fonts" },
219     /* Ghostscript */
220     { "c:\\gs\\fonts" },
221     /* X11 */
222     { "$(CYGWIN_ROOT)\\usr\\X11R6\\lib\\X11\\fonts\\Type1" },
223 #ifdef HAVE_KPSEXPAND
224     /* fpTeX */
225     { "$`kpsewhich -expand-path=$HOMETEXMF`\\fonts\\type1!" },
226     { "$`kpsewhich -expand-path=$TEXMFLOCAL`\\fonts\\type1!" },
227     { "$`kpsewhich -expand-path=$TEXMFMAIN`\\fonts\\type1!" },
228     { "$`kpsewhich -expand-path=$TEXMFDIST`\\fonts\\type1!" },
229 #endif
230     { NULL }
231 };
232 #endif
233
234 #if defined(_Macintosh) && !defined(FONTPATHSET)
235 #  define FONTPATHSET
236 static const struct path_table fontpath_tbl[] =
237 {
238     { "/System/Library/Fonts!" },
239     { "/Library/Fonts!" },
240     { "$(HOME)/Library/Fonts!" },
241     { NULL }
242 };
243 #endif
244
245 #if defined(VMS) && !defined(FONTPATHSET)
246 #  define FONTPATHSET
247 static const struct path_table fontpath_tbl[] =
248 {
249     { "SYS$COMMON:[SYSFONT]!" },
250     { NULL }
251 };
252 #endif
253
254 /* Fallback: Should work for unix */
255 #ifndef FONTPATHSET
256 static const struct path_table fontpath_tbl[] =
257 {
258 #ifdef HAVE_KPSEXPAND
259     /* teTeX or TeXLive */
260     { "$`kpsexpand '$HOMETEXMF'`/fonts/type1!" },
261     { "$`kpsexpand '$TEXMFLOCAL'`/fonts/type1!" },
262     { "$`kpsexpand '$TEXMFMAIN'`/fonts/type1!" },
263     { "$`kpsexpand '$TEXMFDIST'`/fonts/type1!" },
264 #endif
265     /* Linux paths */
266     { "/usr/X11R6/lib/X11/fonts/Type1" },
267     { "/usr/X11R6/lib/X11/fonts/truetype" },
268     /* HP-UX */
269     { "/usr/lib/X11/fonts!"},
270     /* Ghostscript */
271     { "/usr/share/ghostscript/fonts" },
272     { "/usr/local/share/ghostscript/fonts" },
273     { NULL }
274 };
275 #endif
276
277 #undef FONTPATHSET
278
279 static TBOOLEAN fontpath_init_done = FALSE;
280
281 /*
282  * char *fontpath_handler (int, char *)
283  *
284  */
285 char *
286 fontpath_handler(int action, char *path)
287 {
288     /* fontpath variable
289      * the path elements are '\0' separated (!)
290      * this way, reading out fontpath is very
291      * easy to implement */
292     static char *fontpath;
293     /* index pointer, end of fontpath,
294      * env section of fontpath, current limit, in that order */
295     static char *p, *last, *envptr, *limit;
296
297     if (!fontpath_init_done) {
298         fontpath_init_done = TRUE;
299         init_fontpath();
300     }
301
302     switch (action) {
303     case ACTION_CLEAR:
304         /* Clear fontpath, fall through to init */
305         FPRINTF((stderr, "Clear fontpath\n"));
306         free(fontpath);
307         fontpath = p = last = NULL;
308         /* HBB 20000726: 'limit' has to be initialized to NULL, too! */
309         limit = NULL;
310     case ACTION_INIT:
311         /* Init fontpath from environment */
312         FPRINTF((stderr, "Init fontpath from environment\n"));
313         assert(fontpath == NULL);
314         if (!fontpath)
315         {
316             char *envlib = getenv("GNUPLOT_FONTPATH");
317             if (envlib) {
318                 /* get paths from environment */
319                 int len = strlen(envlib);
320                 fontpath = gp_strdup(envlib);
321                 /* point to end of fontpath */
322                 last = fontpath + len;
323                 /* convert all PATHSEPs to \0 */
324                 PATHSEP_TO_NUL(fontpath);
325             }
326 #if defined(HAVE_DIRENT_H) || defined(_Windows)
327             else {
328                 /* set hardcoded paths */
329                 const struct path_table *curr_fontpath = fontpath_tbl;
330
331                 while (curr_fontpath->dir) {
332                     char *currdir = NULL;
333                     char *envbeg = NULL;
334 #  if defined(PIPES)
335                     char *cmdbeg = NULL;
336 #  endif
337                     TBOOLEAN subdirs = FALSE;
338
339                     currdir = gp_strdup( curr_fontpath->dir );
340
341                     while ( (envbeg=strstr(currdir, "$("))
342 #  if defined(PIPES)
343                             || (cmdbeg=strstr( currdir, "$`" ))
344 #  endif
345                             ) {
346                         /* Read environment variables */
347                         if (envbeg) {
348                             char *tmpdir = NULL;
349                             char *envend = NULL, *envval = NULL;
350                             unsigned int envlen;
351                             envend = strchr(envbeg+2,')');
352                             envend[0] = '\0';
353                             envval = getenv(envbeg+2);
354                             envend[0] = ')';
355                             envlen = envval ? strlen(envval) : 0;
356                             tmpdir = gp_alloc(strlen(currdir)+envlen
357                                               +envbeg-envend+1,
358                                               "expand fontpath");
359                             strncpy(tmpdir,currdir,envbeg-currdir);
360                             if (envval)
361                                 strcpy(tmpdir+(envbeg-currdir),envval);
362                             strcpy(tmpdir+(envbeg-currdir+envlen), envend+1);
363
364                             free(currdir);
365                             currdir = tmpdir;
366                         }
367 #  if defined(PIPES)
368                         /* Read environment variables */
369                         else if (cmdbeg) {
370                             char *tmpdir = NULL;
371                             char *envend = NULL;
372                             char envval[256];
373                             unsigned int envlen;
374                             FILE *fcmd;
375                             envend = strchr(cmdbeg+2,'`');
376                             envend[0] = '\0';
377                             fcmd = popen(cmdbeg+2,"r");
378                             if (fcmd) {
379                                 fgets(envval,255,fcmd);
380                                 if (envval[strlen(envval)-1]=='\n')
381                                     envval[strlen(envval)-1]='\0';
382                                 pclose(fcmd);
383                             }
384                             envend[0] = '`';
385                             envlen = strlen(envval);
386                             tmpdir = gp_alloc(strlen(currdir)+envlen
387                                               +cmdbeg-envend+1,
388                                               "expand fontpath");
389                             strncpy(tmpdir,currdir,cmdbeg-currdir);
390                             strcpy(tmpdir+(cmdbeg-currdir),envval);
391                             strcpy(tmpdir+(cmdbeg-currdir+envlen), envend+1);
392
393                             free(currdir);
394                             currdir = tmpdir;
395                         }
396 #  endif
397                     }
398
399                     if ( currdir[strlen(currdir)-1] == '!' ) {
400                         /* search subdirectories */
401                         /* delete ! from directory name */
402                         currdir[strlen(currdir)-1] = '\0';
403                         subdirs = TRUE;
404                     }
405
406                     if ( existdir( currdir ) ) {
407                         size_t plen;
408                         if ( subdirs )
409                             /* add ! to directory name again */
410                             currdir[strlen(currdir)] = '!';
411                         plen = strlen(currdir);
412                         if (fontpath) {
413                             size_t elen = strlen(fontpath);
414                             fontpath = gp_realloc(fontpath,
415                                                   elen + 1 + plen + 1,
416                                                   "expand fontpath");
417                             last = fontpath+elen;
418                             *last = PATHSEP;
419                             ++last;
420                             *last = '\0';
421                         } else {
422                             fontpath = gp_alloc(plen + 1,
423                                                 "expand fontpath");
424                             last = fontpath;
425                         }
426
427                         strcpy(last, currdir );
428                         last += plen;
429                     }
430                     curr_fontpath++;
431                     if (currdir) {
432                         free(currdir);
433                         currdir = NULL;
434                     }
435                 }
436                 /* convert all PATHSEPs to \0 */
437                 if (fontpath)
438                     PATHSEP_TO_NUL(fontpath);
439             }
440 #endif /* HAVE_DIRENT_H */
441
442         }                       /* else: already initialised; int_warn (?) */
443         /* point to env portion of fontpath */
444         envptr = fontpath;
445         break;
446     case ACTION_SET:
447         /* set the fontpath */
448         FPRINTF((stderr, "Set fontpath\n"));
449         if (path && *path != NUL) {
450             /* length of env portion */
451             size_t elen = last - envptr;
452             size_t plen = strlen(path);
453             if (fontpath && envptr) {
454                 /* we are prepending a path name; because
455                  * realloc() preserves only the contents up
456                  * to the minimum of old and new size, we move
457                  * the part to be preserved to the beginning
458                  * of the string; use memmove() because strings
459                  * may overlap */
460                 memmove(fontpath, envptr, elen + 1);
461             }
462             fontpath = gp_realloc(fontpath, elen + 1 + plen + 1, "expand fontpath");
463             /* now move env part back to the end to make space for
464              * the new path */
465             memmove(fontpath + plen + 1, fontpath, elen + 1);
466             strcpy(fontpath, path);
467             /* separate new path(s) and env path(s) */
468             fontpath[plen] = PATHSEP;
469             /* adjust pointer to env part and last */
470             envptr = &fontpath[plen+1];
471             last = envptr + elen;
472             PATHSEP_TO_NUL(fontpath);
473         }                       /* else: NULL = empty */
474         break;
475     case ACTION_SHOW:
476         /* print the current, full fontpath */
477         FPRINTF((stderr, "Show fontpath\n"));
478         if (fontpath) {
479             fputs("\tfontpath is ", stderr);
480             PRINT_PATHLIST(fontpath, envptr);
481             if (envptr) {
482                 /* env part */
483                 fputs("\tsystem fontpath is ", stderr);
484                 PRINT_PATHLIST(envptr, last);
485             }
486         } else
487             fputs("\tfontpath is empty\n", stderr);
488         break;
489     case ACTION_SAVE:
490         /* we don't save the font path taken from the
491          * environment, so don't go beyond envptr when
492          * extracting the path elements
493          */
494         limit = envptr;
495     case ACTION_GET:
496         /* subsequent calls to get_fontpath() return all
497          * elements of the fontpath until exhausted
498          */
499         FPRINTF((stderr, "Get fontpath\n"));
500         if (!fontpath)
501             return NULL;
502         if (!p) {
503             /* init section */
504             p = fontpath;
505             if (!limit)
506                 limit = last;
507         } else {
508             /* skip over '\0' */
509             p += strlen(p) + 1;
510         }
511         if (p >= limit)
512             limit = p = NULL;
513         return p;
514     case ACTION_NULL:
515         /* just return */
516     default:
517         break;
518     }
519
520     /* should always be ignored - points to the
521      * first path in the list */
522     return fontpath;
523
524 }
525
526 /* not set or shown directly, but controlled by 'set locale'
527  * defined in national.h
528  */
529
530 char full_month_names[12][32] =
531 { FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
532 char abbrev_month_names[12][8] =
533 { AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };
534
535 char full_day_names[7][32] =
536 { FDAY0, FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6 };
537 char abbrev_day_names[7][8] =
538 { ADAY0, ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6 };
539
540 char *
541 locale_handler(int action, char *newlocale)
542 {
543     static char *current_locale = NULL;
544     struct tm tm;
545     int i;
546
547     switch(action) {
548     case ACTION_CLEAR:
549     case ACTION_INIT:
550         if (current_locale) free(current_locale);
551         current_locale = gp_strdup(INITIAL_LOCALE);
552         break;
553     case ACTION_SET:
554 /* FIXME: configure test for setlocale() */
555 #ifdef HAVE_LOCALE_H
556         if (setlocale(LC_TIME, newlocale)) {
557             current_locale = gp_realloc(current_locale, strlen(newlocale) + 1, "locale");
558             strcpy(current_locale, newlocale);
559         }
560         else
561             int_error(c_token, "Locale not available");
562
563         /* we can do a *lot* better than this ; eg use system functions
564          * where available; create values on first use, etc
565          */
566         memset(&tm, 0, sizeof(struct tm));
567         for (i = 0; i < 7; ++i) {
568             tm.tm_wday = i;             /* hope this enough */
569             strftime(full_day_names[i], sizeof(full_day_names[i]), "%A", &tm);
570             strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%a", &tm);
571         }
572         for (i = 0; i < 12; ++i) {
573             tm.tm_mon = i;              /* hope this enough */
574             strftime(full_month_names[i], sizeof(full_month_names[i]), "%B", &tm);
575             strftime(abbrev_month_names[i], sizeof(abbrev_month_names[i]), "%b", &tm);
576         }
577 #else
578         current_locale = gp_realloc(current_locale, strlen(newlocale) + 1, "locale");
579         strcpy(current_locale, newlocale);
580 #endif /* HAVE_LOCALE_H */
581         break;
582     case ACTION_SHOW:
583 #ifdef HAVE_LOCALE_H
584         fprintf(stderr, "\tLC_CTYPE is %s\n", setlocale(LC_CTYPE,NULL));
585         fprintf(stderr, "\tLC_TIME is %s\n", setlocale(LC_TIME,NULL));
586 #else
587         fprintf(stderr, "\tlocale is \"%s\"\n", current_locale);
588 #endif
589         break;
590     case ACTION_SAVE:
591     case ACTION_GET:
592     case ACTION_NULL:
593     default:
594         /* just return */
595         break;
596     }
597
598     return current_locale;
599 }
600