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