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