1 /*
2  * Grace - GRaphing, Advanced Computation and Exploration of data
3  *
4  * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5  *
6  * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7  * Copyright (c) 1996-2007 Grace Development Team
8  *
9  * Maintained by Evgeny Stambulchik
10  *
11  *
12  *                           All Rights Reserved
13  *
14  *    This program is free software; you can redistribute it and/or modify
15  *    it under the terms of the GNU General Public License as published by
16  *    the Free Software Foundation; either version 2 of the License, or
17  *    (at your option) any later version.
18  *
19  *    This program is distributed in the hope that it will be useful,
20  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *    GNU General Public License for more details.
23  *
24  *    You should have received a copy of the GNU General Public License
25  *    along with this program; if not, write to the Free Software
26  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  */
28 
29 /*
30  * misc utilities
31  *
32  */
33 
34 #include <config.h>
35 #include <cmath.h>
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <pwd.h>
43 #ifdef TIME_WITH_SYS_TIME
44 #  include <sys/time.h>
45 #  include <time.h>
46 #else
47 #  ifdef HAVE_SYS_TIME_H
48 #    include <sys/time.h>
49 #  else
50 #    include <time.h>
51 #  endif
52 #endif
53 #include <signal.h>
54 #include <sys/types.h>
55 #include <sys/resource.h>
56 #ifdef HAVE_SYS_SELECT_H
57 #  include <sys/select.h>
58 #endif
59 #include <limits.h>
60 
61 #ifdef HAVE_SETLOCALE
62 #  include <locale.h>
63 #endif
64 
65 #include "buildinfo.h"
66 
67 #include "globals.h"
68 #include "utils.h"
69 #include "files.h"
70 #include "protos.h"
71 
72 static void rereadConfig(void);
73 static RETSIGTYPE actOnSignal(int signo);
74 static void bugwarn(char *signame);
75 
76 /*
77  * free and check for NULL pointer
78  */
xfree(void * ptr)79 void xfree(void *ptr)
80 {
81     if (ptr != NULL) {
82 	free(ptr);
83     }
84 }
85 
xmalloc(size_t size)86 void *xmalloc(size_t size)
87 {
88     void *retval;
89 
90     if (size == 0) {
91         retval = NULL;
92     } else {
93         retval = malloc(size);
94     }
95 
96     if (retval == NULL && size != 0) {
97         errmsg("Memory storage exceeded!");
98     }
99     return retval;
100 }
101 
xcalloc(size_t nmemb,size_t size)102 void *xcalloc(size_t nmemb, size_t size)
103 {
104     void *retval;
105 
106     if (nmemb == 0) {
107         retval = NULL;
108     } else {
109         retval = calloc(nmemb, size);
110     }
111 
112     if (retval == NULL && nmemb != 0) {
113         errmsg("Memory storage exceeded!");
114     }
115     return retval;
116 }
117 
xrealloc(void * ptr,size_t size)118 void *xrealloc(void *ptr, size_t size)
119 {
120     void *retval;
121 
122 #if defined(REALLOC_IS_BUGGY)
123     if (ptr == NULL) {
124         retval = malloc(size);
125     } else if (size == 0) {
126         xfree(ptr);
127         retval = NULL;
128     } else {
129         retval = realloc(ptr, size);
130     }
131 #else
132     retval = realloc(ptr, size);
133     if (size == 0) {
134         retval = NULL;
135     }
136 #endif
137 
138     if (retval == NULL && size != 0) {
139         errmsg("Memory storage exceeded!");
140     }
141     return retval;
142 }
143 
144 /*
145  * swap doubles and ints
146  */
fswap(double * x,double * y)147 void fswap(double *x, double *y)
148 {
149     double tmp;
150 
151     tmp = *x;
152     *x = *y;
153     *y = tmp;
154 }
155 
iswap(int * x,int * y)156 void iswap(int *x, int *y)
157 {
158     int tmp;
159 
160     tmp = *x;
161     *x = *y;
162     *y = tmp;
163 }
164 
isoneof(int c,char * s)165 int isoneof(int c, char *s)
166 {
167     while (*s) {
168 	if (c == *s) {
169 	    return 1;
170 	} else {
171 	    s++;
172 	}
173     }
174     return 0;
175 }
176 
argmatch(char * s1,char * s2,int atleast)177 int argmatch(char *s1, char *s2, int atleast)
178 {
179     int l1 = strlen(s1);
180     int l2 = strlen(s2);
181 
182     if (l1 < atleast) {
183 	return 0;
184     }
185     if (l1 > l2) {
186 	return 0;
187     }
188     return (strncmp(s1, s2, l1) == 0);
189 }
190 
191 /*
192  * convert a string from lower to upper case
193  * leaving quoted strings alone
194  */
lowtoupper(char * s)195 void lowtoupper(char *s)
196 {
197     int i, quoteon = FALSE;
198 
199     for (i = 0; i < strlen(s); i++) {
200 	if (s[i] == '"') {
201 	    if (!quoteon) {
202 		quoteon = TRUE;
203 	    } else if ((i > 0) && (s[i-1] != '\\')) {
204 		quoteon = FALSE;
205 	    }
206 	}
207 	if (quoteon == FALSE) {
208             if (!isprint(s[i])) {
209                 s[i] = ' ';
210             } else if (s[i] >= 'a' && s[i] <= 'z') {
211 	        s[i] -= ' ';
212 	    }
213         }
214     }
215 }
216 
217 /*
218  * remove all that fortran nastiness
219  */
convertchar(char * s)220 void convertchar(char *s)
221 {
222     while (*s++) {
223 	if (*s == ',')
224 	    *s = ' ';
225 	if (*s == 'D' || *s == 'd')
226 	    *s = 'e';
227     }
228 }
229 
230 /*
231  * log base 2
232  */
ilog2(int n)233 int ilog2(int n)
234 {
235     int i = 0;
236     int n1 = n;
237 
238     while (n1 >>= 1)
239 	i++;
240     if (1 << i != n)
241 	return -1;
242     else
243 	return i;
244 }
245 
246 /*
247  * compute the area bounded by the polygon (xi,yi)
248  */
comp_area(int n,double * x,double * y)249 double comp_area(int n, double *x, double *y)
250 {
251     int i;
252     double sum = 0.0;
253 
254     for (i = 0; i < n; i++) {
255 	sum = sum + x[i] * y[(i + 1) % n] - y[i] * x[(i + 1) % n];
256     }
257     return sum * 0.5;
258 }
259 
260 /*
261  * compute the perimeter bounded by the polygon (xi,yi)
262  */
comp_perimeter(int n,double * x,double * y)263 double comp_perimeter(int n, double *x, double *y)
264 {
265     int i;
266     double sum = 0.0;
267 
268     for (i = 0; i < n - 1; i++) {
269 	sum = sum + hypot(x[i] - x[(i + 1) % n], y[i] - y[(i + 1) % n]);
270     }
271     return sum;
272 }
273 
274 char *dayofweekstrs[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
275 char *dayofweekstrl[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
276 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
277 char *monthl[] = {"January", "February", "March", "April", "May", "June",
278 "July", "August", "September", "October", "November", "December"};
279 
dayofweek(double j)280 int dayofweek(double j)
281 {
282     int i = (int) floor(j + 1.5);
283     return (i <= 0) ? 6 - (6 - i)%7 : i%7;
284 }
285 
286 /*
287  * escape quotes
288  */
escapequotes(char * s)289 char *escapequotes (char *s)
290 {
291     static char *es = NULL;
292     int i, k, n, len, elen;
293 
294     if (s == NULL)
295         return NULL;
296 
297     len = strlen(s);
298     es = xrealloc(es, (len + 1)*SIZEOF_CHAR);
299     strcpy(es, s);
300     n = 0;
301     while ((es = strchr(es, '\"'))) {
302     	es++;
303     	n++;
304     }
305 
306     elen = len + n + 1;
307     es = xrealloc(es, elen*SIZEOF_CHAR);
308 
309     i = k = 0;
310     while (i < len) {
311         if (s[i] == '\"') {
312             es[k] = '\\';
313             k++;
314         }
315         es[k] = s[i];
316         i++; k++;
317     }
318     es[elen-1] = '\0';
319     return es;
320 }
321 
sign(double a)322 int sign(double a)
323 {
324     if (a > 0.0) {
325         return +1;
326     } else if (a < 0.0) {
327         return -1;
328     } else {
329         return 0;
330     }
331 }
332 
mytrunc(double a)333 double mytrunc(double a)
334 {
335     if (a > 0.0) {
336         return floor(a);
337     } else {
338         return ceil(a);
339     }
340 }
341 
342 /*
343  * exit grace
344  */
bailout(void)345 void bailout(void)
346 {
347     if (!is_dirtystate() || yesno("Exit losing unsaved changes?", NULL, NULL, NULL)) {
348          if (resfp) {
349              grace_close(resfp);
350          }
351          exit(0);
352     }
353 }
354 
355 /*
356  * Reread config (TODO)
357  */
rereadConfig(void)358 static void rereadConfig(void)
359 {
360     getparms("gracerc");
361 }
362 
please_report_the_bug(void)363 static void please_report_the_bug(void)
364 {
365     fprintf(stderr, "\nPlease use \"Help/Comments\" to report the bug.\n");
366 #ifdef HAVE_LESSTIF
367     fprintf(stderr, "NB. This version of Grace was compiled with LessTif.\n");
368     fprintf(stderr, "    Make sure to read the FAQ carefully prior to\n");
369     fprintf(stderr, "    reporting the bug, ESPECIALLY is the problem might\n");
370     fprintf(stderr, "    be related to the graphical interface.\n");
371 #endif
372 }
373 
374 /*
375  * Warn about bug (TODO X message)
376  */
bugwarn(char * signame)377 static void bugwarn(char *signame)
378 {
379     static int emergency_save = FALSE;
380 /*
381  *  Since we got so far, memory is probably corrupted so it's better to use
382  *  a static storage
383  */
384     static char buf[GR_MAXPATHLEN];
385 /* number of interrupts received during the emergency save */
386     static int interrupts;
387 
388     if (emergency_save != FALSE) {
389         /* don't mind signals anymore: we're in emergency save mode already */
390         interrupts++;
391         if (interrupts > 10) {
392             fprintf(stderr, "oh, no luck :-(\n");
393             please_report_the_bug();
394             abort();
395         }
396         return;
397     } else {
398         emergency_save = TRUE;
399         interrupts = 0;
400         fprintf(stderr, "\a\nOops! Got %s\n", signame);
401         if (is_dirtystate()) {
402             strcpy(buf, get_docname());
403             strcat(buf, "$");
404             fprintf(stderr, "Trying to save your work into file \"%s\"... ", buf);
405             fflush(stderr);
406             noask = TRUE;
407             if (save_project(buf) == RETURN_SUCCESS) {
408                 fprintf(stderr, "ok!\n");
409             } else {
410                 fprintf(stderr, "oh, no luck :-(\n");
411             }
412         }
413         please_report_the_bug();
414         abort();
415     }
416 }
417 
418 /*
419  * Signal-handling routines
420  */
421 
actOnSignal(int signo)422 static RETSIGTYPE actOnSignal(int signo)
423 {
424     char signame[16];
425 
426     installSignal();
427 
428     switch (signo) {
429 #ifdef SIGHUP
430     case SIGHUP:
431     	rereadConfig();
432     	break;
433 #endif
434 #ifdef SIGINT
435     case SIGINT:
436 #endif
437 #ifdef SIGQUIT
438     case SIGQUIT:
439 #endif
440 #ifdef SIGTERM
441     case SIGTERM:
442 #endif
443         bailout();
444         break;
445 #ifdef SIGILL
446     case SIGILL:
447         strcpy(signame, "SIGILL");
448 #endif
449 #ifdef SIGFPE
450     case SIGFPE:
451         strcpy(signame, "SIGFPE");
452 #endif
453 #ifdef SIGBUS
454     case SIGBUS:
455         strcpy(signame, "SIGBUS");
456 #endif
457 #ifdef SIGSEGV
458     case SIGSEGV:
459         strcpy(signame, "SIGSEGV");
460 #endif
461 #ifdef SIGSYS
462     case SIGSYS:
463         strcpy(signame, "SIGSYS");
464 #endif
465         bugwarn(signame);
466         break;
467     default:
468         break;
469     }
470 }
471 
installSignal(void)472 void installSignal(void){
473 #ifdef SIGHUP
474     signal(SIGHUP,  actOnSignal);   /* hangup */
475 #endif
476 #ifdef SIGINT
477     signal(SIGINT,  actOnSignal);   /* interrupt */
478 #endif
479 #ifdef SIGQUIT
480     signal(SIGQUIT, actOnSignal);   /* quit */
481 #endif
482 #ifdef SIGILL
483     signal(SIGILL,  actOnSignal);   /* illegal instruction */
484 #endif
485 #ifdef SIGFPE
486     signal(SIGFPE,  actOnSignal);   /* floating point exception */
487 #endif
488 #ifdef SIGBUS
489     signal(SIGBUS,  actOnSignal);   /* bus error */
490 #endif
491 #ifdef SIGSEGV
492     signal(SIGSEGV, actOnSignal);   /* segmentation violation */
493 #endif
494 #ifdef SIGSYS
495     signal(SIGSYS,  actOnSignal);   /* bad argument to system call */
496 #endif
497 #ifdef SIGTERM
498     signal(SIGTERM, actOnSignal);   /* software termination signal */
499 #endif
500 #ifdef SIGALRM
501     signal(SIGALRM, actOnSignal);   /* timer */
502 #endif
503 #ifdef SIGIO
504     signal(SIGIO, actOnSignal);     /* input/output ready */
505 #endif
506 }
507 
508 
509 /* create format string */
create_fstring(int form,int prec,double loc,int type)510 char *create_fstring(int form, int prec, double loc, int type)
511 {
512     char format[64], *eng_prefix,*comp_prefix;
513     static char s[MAX_STRING_LENGTH];
514     double tmp;
515     int m, d, y, h, mm, sec;
516     double arcmin, arcsec;
517     int exponent;
518     double mantissa;
519     int yprec;
520 
521     if (two_digits_years_allowed()) {
522         yprec = 2;
523     } else {
524         yprec = 4;
525     }
526 
527     /* for locale decimal points */
528     set_locale_num(TRUE);
529 
530     strcpy(format, "%.*lf");
531     switch (form) {
532     case FORMAT_DECIMAL:
533 	sprintf(s, format, prec, loc);
534 	tmp = atof(s);		/* fix reverse axes problem when loc == -0.0 */
535 	if (tmp == 0.0) {
536 	    strcpy(format, "%.*lf");
537 	    loc = 0.0;
538 	    sprintf(s, format, prec, loc);
539 	}
540 	break;
541     case FORMAT_EXPONENTIAL:
542 	strcpy(format, "%.*le");
543 	sprintf(s, format, prec, loc);
544 	tmp = atof(s);		/* fix reverse axes problem when loc == -0.0 */
545 	if (tmp == 0.0) {
546 	    strcpy(format, "%.*le");
547 	    loc = 0.0;
548 	    sprintf(s, format, prec, loc);
549 	}
550 	break;
551     case FORMAT_SCIENTIFIC:
552 	if (loc != 0.0) {
553             exponent = (int) floor(log10(fabs(loc)));
554             mantissa = loc/pow(10.0, (double) exponent);
555             if (type == LFORMAT_TYPE_EXTENDED) {
556 	        strcpy(format, "%.*f\\x\\c4\\C\\f{}10\\S%d\\N");
557 	    } else {
558 	        strcpy(format, "%.*fx10(%d)");
559             }
560 	    sprintf(s, format, prec, mantissa, exponent);
561         } else {
562 	    strcpy(format, "%.*f");
563 	    sprintf(s, format, prec, 0.0);
564         }
565 	break;
566     case FORMAT_COMPUTING:
567         /* As per FORMAT_GENERAL but uses computer notation (K,M,G,...)
568          * to give the value in multiples of the powers of 1024
569          */
570         if (loc != 0.0) {
571             exponent = (int) floor(log2(fabs(loc)));
572             if (exponent < 10) {
573                 exponent = 0;
574             } else if (exponent > 80) {
575                 exponent = 80;
576             } else {
577                 exponent = (int) floor((double) exponent/10)*10;
578             }
579         } else {
580             exponent = 0;
581         }
582 
583         /* use next prefix if we would get 1024 because
584         ** of the print precision requested.  This happens
585         ** for values slightly less than 1024.
586         */
587         sprintf(s, "%.*g", prec, loc/(pow(2.0, exponent)));
588         if ((exponent < 80) && (strcmp(s, "1024") == 0)){
589 	    exponent += 10;
590 	}
591 
592         switch (exponent) {
593         case 10: /* kilo */
594             comp_prefix = "K";
595             break;
596         case 20: /* Mega */
597             comp_prefix = "M";
598             break;
599         case 30: /* Giga */
600             comp_prefix = "G";
601             break;
602         case 40: /* Tera */
603             comp_prefix = "T";
604             break;
605         case 50: /* Peta */
606             comp_prefix = "P";
607             break;
608         case 60: /* Exa */
609             comp_prefix = "E";
610             break;
611         case 70: /* Zetta */
612             comp_prefix = "Z";
613             break;
614         case 80: /* Yotta */
615             comp_prefix = "Y";
616             break;
617         default:
618             comp_prefix = "";
619             break;
620         }
621         sprintf(s,"%.*g%s", prec, loc/(pow(2.0, exponent)), comp_prefix);
622         tmp = atof(s);          /* fix reverse axes problem when loc == -0.0 */
623         if (tmp == 0.0) {
624             strcpy(format, "%lg");
625             loc = 0.0;
626             sprintf(s, format, loc);
627         }
628 	break;
629     case FORMAT_ENGINEERING:
630 	if (loc != 0.0) {
631             exponent = (int) floor(log10(fabs(loc)));
632             if (exponent < -24) {
633                 exponent = -24;
634             } else if (exponent > 24) {
635                 exponent = 24;
636             } else {
637                 exponent = (int) floor((double) exponent/3)*3;
638             }
639         } else {
640             exponent = 0;
641         }
642         switch (exponent) {
643         case -24: /* yocto */
644             eng_prefix = "y";
645             break;
646         case -21: /* zepto */
647             eng_prefix = "z";
648             break;
649         case -18: /* atto */
650             eng_prefix = "a";
651             break;
652         case -15: /* fempto */
653             eng_prefix = "f";
654             break;
655         case -12: /* pico */
656             eng_prefix = "p";
657             break;
658         case -9: /* nano */
659             eng_prefix = "n";
660             break;
661         case -6: /* micro */
662             if (type == LFORMAT_TYPE_EXTENDED) {
663                 eng_prefix = "\\xm\\f{}";
664             } else {
665                 eng_prefix = "mk";
666             }
667             break;
668         case -3: /* milli */
669             eng_prefix = "m";
670             break;
671         case 3: /* kilo */
672             eng_prefix = "k";
673             break;
674         case 6: /* Mega */
675             eng_prefix = "M";
676             break;
677         case 9: /* Giga */
678             eng_prefix = "G";
679             break;
680         case 12: /* Tera */
681             eng_prefix = "T";
682             break;
683         case 15: /* Peta */
684             eng_prefix = "P";
685             break;
686         case 18: /* Exa */
687             eng_prefix = "E";
688             break;
689         case 21: /* Zetta */
690             eng_prefix = "Z";
691             break;
692         case 24: /* Yotta */
693             eng_prefix = "Y";
694             break;
695         default:
696             eng_prefix = "";
697             break;
698         }
699 	strcpy(format, "%.*f %s");
700 	sprintf(s, format, prec, loc/(pow(10.0, exponent)), eng_prefix);
701 	break;
702     case FORMAT_POWER:
703         if (loc < 0.0) {
704             loc = log10(-loc);
705             if (type == LFORMAT_TYPE_EXTENDED) {
706                 strcpy(format, "-10\\S%.*lf\\N");
707             } else {
708                 strcpy(format, "-10(%.*lf)\\N");
709             }
710         } else if (loc == 0.0) {
711             sprintf(format, "%.*f", prec, 0.0);
712         } else {
713             loc = log10(loc);
714             if (type == LFORMAT_TYPE_EXTENDED) {
715                 strcpy(format, "10\\S%.*lf\\N");
716             } else {
717                 strcpy(format, "10(%.*lf)\\N");
718             }
719         }
720         sprintf(s, format, prec, loc);
721         break;
722     case FORMAT_GENERAL:
723 	strcpy(format, "%.*lg");
724 	sprintf(s, format, prec, loc);
725 	tmp = atof(s);
726 	if (tmp == 0.0) {
727 	    strcpy(format, "%lg");
728 	    loc = 0.0;
729 	    sprintf(s, format, loc);
730 	}
731 	break;
732     case FORMAT_DDMMYY:
733 	strcpy(format, "%02d-%02d-%0*d");
734 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
735 	sprintf(s, format, d, m, yprec, y);
736 	break;
737     case FORMAT_MMDDYY:
738 	strcpy(format, "%02d-%02d-%0*d");
739 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
740 	sprintf(s, format, m, d, yprec, y);
741 	break;
742     case FORMAT_YYMMDD:
743 	strcpy(format, "%0*d-%02d-%02d");
744 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
745 	sprintf(s, format, yprec, y, m, d);
746 	break;
747     case FORMAT_MMYY:
748 	strcpy(format, "%02d-%0*d");
749 	jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec);
750 	sprintf(s, format, m, yprec, y);
751 	break;
752     case FORMAT_MMDD:
753 	strcpy(format, "%02d-%02d");
754 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
755 	sprintf(s, format, m, d);
756 	break;
757     case FORMAT_MONTHDAY:
758 	strcpy(format, "%s-%02d");
759 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
760 	if (m - 1 < 0 || m - 1 > 11) {
761 	    sprintf(s, format, "???");
762 	} else {
763 	    sprintf(s, format, months[m - 1], d);
764 	}
765 	break;
766     case FORMAT_DAYMONTH:
767 	strcpy(format, "%02d-%s");
768 	jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
769 	if (m - 1 < 0 || m - 1 > 11) {
770 	    sprintf(s, format, "???");
771 	} else {
772 	    sprintf(s, format, d, months[m - 1]);
773 	}
774 	break;
775     case FORMAT_MONTHS:
776 	strcpy(format, "%s");
777 	jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec);
778 	if (m - 1 < 0 || m - 1 > 11) {
779 	    sprintf(s, format, "???");
780 	} else {
781 	    sprintf(s, format, months[m - 1]);
782 	}
783 	break;
784     case FORMAT_MONTHSY:
785 	strcpy(format, "%s-%0*d");
786 	jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec);
787 	if (m - 1 < 0 || m - 1 > 11) {
788 	    sprintf(s, format, "???");
789 	} else {
790 	    sprintf(s, format, months[m - 1], yprec, y);
791 	}
792 	break;
793     case FORMAT_MONTHL:
794 	strcpy(format, "%s");
795 	jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec);
796 	if (m - 1 < 0 || m - 1 > 11) {
797 	    sprintf(s, format, "???");
798 	} else {
799 	    sprintf(s, format, monthl[m - 1]);
800 	}
801 	break;
802     case FORMAT_DAYOFWEEKS:
803 	strcpy(format, "%s");
804 	sprintf(s, format, dayofweekstrs[dayofweek(loc + get_ref_date())]);
805 	break;
806     case FORMAT_DAYOFWEEKL:
807 	strcpy(format, "%s");
808 	sprintf(s, format, dayofweekstrl[dayofweek(loc + get_ref_date())]);
809 	break;
810     case FORMAT_DAYOFYEAR:
811 	strcpy(format, "%d");
812         jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec);
813 	sprintf(s, format,
814                 1 + (int) (cal_to_jul(y, m, d) - cal_to_jul(y, 1, 1)));
815 	break;
816     case FORMAT_HMS:
817 	strcpy(format, "%02d:%02d:%02d");
818 	jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec);
819 	sprintf(s, format, h, mm, sec);
820 	break;
821     case FORMAT_MMDDHMS:
822 	strcpy(format, "%02d-%02d %02d:%02d:%02d");
823 	jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec);
824 	sprintf(s, format, m, d, h, mm, sec);
825 	break;
826     case FORMAT_MMDDYYHMS:
827 	strcpy(format, "%02d-%02d-%d %02d:%02d:%02d");
828 	jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec);
829 	sprintf(s, format, m, d, y, h, mm, sec);
830 	break;
831     case FORMAT_YYMMDDHMS:
832 	strcpy(format, "%0*d-%02d-%02d %02d:%02d:%02d");
833 	jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec);
834 	sprintf(s, format, yprec, y, m, d, h, mm, sec);
835 	break;
836     case FORMAT_DEGREESLON:
837 	if (loc < 0.0) {
838 	    loc *= -1.0;
839 	    strcpy(format, "%.*lfW");
840 	} else if (loc > 0.0) {
841 	    strcpy(format, "%.*lfE");
842 	} else {
843 	    strcpy(format, "0");
844 	}
845 	sprintf(s, format, prec, loc);
846 	break;
847     case FORMAT_DEGREESMMLON:
848 	if (loc < 0.0) {
849 	    loc *= -1.0;
850 	    strcpy(format, "%d %.*lf' W");
851 	} else if (loc > 0.0) {
852 	    strcpy(format, "%d %.*lf' E");
853 	} else {
854 	    strcpy(format, "0 0'");
855 	}
856 	y = loc;
857 	arcmin = (loc - y) * 60.0;
858 	sprintf(s, format, y, prec, arcmin);
859 	break;
860     case FORMAT_DEGREESMMSSLON:
861 	if (loc < 0.0) {
862 	    loc *= -1.0;
863 	    strcpy(format, "%d %d' %.*lf\" W");
864 	} else if (loc > 0.0) {
865 	    strcpy(format, "%d %d' %.*lf\" E");
866 	} else {
867 	    strcpy(format, "0 0' 0\"");
868 	}
869 	y = loc;
870 	arcsec = (loc - y) * 3600.0;
871 	m = arcsec / 60.0;
872 	arcsec = (arcsec - m * 60);
873 	sprintf(s, format, y, m, prec, arcsec);
874 	break;
875     case FORMAT_MMSSLON:
876 	if (loc < 0.0) {
877 	    loc *= -1.0;
878 	    strcpy(format, "%d' %.*lf\" W");
879 	} else if (loc > 0.0) {
880 	    strcpy(format, "%d' %.*lf\" E");
881 	} else {
882 	    strcpy(format, "0 0' 0\"");
883 	}
884 	y = loc;
885 	arcsec = (loc - y) * 3600.0;
886 	m = arcsec / 60.0;
887 	arcsec = (arcsec - m * 60);
888 	sprintf(s, format, m, prec, arcsec);
889 	break;
890     case FORMAT_DEGREESLAT:
891 	if (loc < 0.0) {
892 	    loc *= -1.0;
893 	    strcpy(format, "%.*lfS");
894 	} else if (loc > 0.0) {
895 	    strcpy(format, "%.*lfN");
896 	} else {
897 	    strcpy(format, "0");
898 	}
899 	sprintf(s, format, prec, loc);
900 	break;
901     case FORMAT_DEGREESMMLAT:
902 	if (loc < 0.0) {
903 	    loc *= -1.0;
904 	    strcpy(format, "%d %.*lf' S");
905 	} else if (loc > 0.0) {
906 	    strcpy(format, "%d %.*lf' N");
907 	} else {
908 	    strcpy(format, "0 0'");
909 	}
910 	y = loc;
911 	arcsec = (loc - y) * 60.0;
912 	sprintf(s, format, y, prec, arcsec);
913 	break;
914     case FORMAT_DEGREESMMSSLAT:
915 	if (loc < 0.0) {
916 	    loc *= -1.0;
917 	    strcpy(format, "%d %d' %.*lf\" S");
918 	} else if (loc > 0.0) {
919 	    strcpy(format, "%d %d' %.*lf\" N");
920 	} else {
921 	    strcpy(format, "0 0' 0\"");
922 	}
923 	y = loc;
924 	arcsec = (loc - y) * 3600.0;
925 	m = arcsec / 60.0;
926 	arcsec = (arcsec - m * 60);
927 	sprintf(s, format, y, m, prec, arcsec);
928 	break;
929     case FORMAT_MMSSLAT:
930 	if (loc < 0.0) {
931 	    loc *= -1.0;
932 	    strcpy(format, "%d' %.*lf\" S");
933 	} else if (loc > 0.0) {
934 	    strcpy(format, "%d' %.*lf\" N");
935 	} else {
936 	    strcpy(format, "0 0' 0\"");
937 	}
938 	y = loc;
939 	arcsec = (loc - y) * 3600.0;
940 	m = arcsec / 60.0;
941 	arcsec = (arcsec - m * 60);
942 	sprintf(s, format, m, prec, arcsec);
943 	break;
944     default:
945 	sprintf(s, format, prec, loc);
946 	break;
947     }
948 
949     /* revert to POSIX */
950     set_locale_num(FALSE);
951 
952     return(s);
953 }
954 
bin_dump(char * value,int i,int pad)955 int bin_dump(char *value, int i, int pad)
956 {
957     char *word;
958 
959     if (i > pad - 1) {
960         return 0;
961     }
962 
963     word = value;
964 
965 #ifdef WORDS_BIGENDIAN
966     return (((*word)>>i)&0x01);
967 #else
968     switch (pad) {
969     case 8:
970         return (((*word)>>i)&0x01);
971         break;
972     case 16:
973         if (i < 8) {
974             word++;
975             return (((*word)>>i)&0x01);
976         } else {
977             return (((*word)>>(8 - i))&0x01);
978         }
979         break;
980     case 32:
981         if (i < 8) {
982             word += 2;
983             return (((*word)>>i)&0x01);
984         } else if (i < 16) {
985             word++;
986             return (((*word)>>(8 - i))&0x01);
987         } else {
988             return (((*word)>>(16 - i))&0x01);
989         }
990         break;
991     default:
992         return 0;
993     }
994 #endif
995 }
996 
reversebits(unsigned char inword)997 unsigned char reversebits(unsigned char inword)
998 {
999     int i;
1000     unsigned char result = 0;
1001 
1002     for (i = 0; i <= 7; i++) {
1003         result |= (((inword)>>i)&0x01)<<(7 - i);
1004     }
1005 
1006     return (result);
1007 }
1008 
copy_string(char * dest,const char * src)1009 char *copy_string(char *dest, const char *src)
1010 {
1011     if (src == dest) {
1012         ;
1013     } else if (src == NULL) {
1014         xfree(dest);
1015         dest = NULL;
1016     } else {
1017         dest = xrealloc(dest, (strlen(src) + 1)*SIZEOF_CHAR);
1018         strcpy(dest, src);
1019     }
1020     return(dest);
1021 }
1022 
concat_strings(char * dest,const char * src)1023 char *concat_strings(char *dest, const char *src)
1024 {
1025     if (src != NULL) {
1026         if (dest == NULL) {
1027             dest = copy_string(NULL, src);
1028         } else {
1029             dest = xrealloc(dest, (strlen(dest) + strlen(src) + 1)*SIZEOF_CHAR);
1030             if (dest != NULL) {
1031                 strcat(dest, src);
1032             }
1033         }
1034     }
1035     return(dest);
1036 }
1037 
compare_strings(const char * s1,const char * s2)1038 int compare_strings(const char *s1, const char *s2)
1039 {
1040     if (s1 == NULL && s2 == NULL) {
1041         return TRUE;
1042     } else if (s1 == NULL || s2 == NULL) {
1043         return FALSE;
1044     } else {
1045         return (strcmp(s1, s2) == 0);
1046     }
1047 }
1048 
1049 /* location of Grace home directory */
1050 static char grace_home[GR_MAXPATHLEN] = GRACE_HOME;
1051 
get_grace_home(void)1052 char *get_grace_home(void)
1053 {
1054     return grace_home;
1055 }
1056 
set_grace_home(const char * dir)1057 void set_grace_home(const char *dir)
1058 {
1059     strncpy(grace_home, dir, GR_MAXPATHLEN - 1);
1060 }
1061 
1062 /* print command */
1063 static char print_cmd[GR_MAXPATHLEN] = GRACE_PRINT_CMD;
1064 
get_print_cmd(void)1065 char *get_print_cmd(void)
1066 {
1067     return print_cmd;
1068 }
1069 
set_print_cmd(const char * cmd)1070 void set_print_cmd(const char *cmd)
1071 {
1072     strncpy(print_cmd, cmd, GR_MAXPATHLEN - 1);
1073 }
1074 
1075 /* editor */
1076 static char grace_editor[GR_MAXPATHLEN] = GRACE_EDITOR;
1077 
get_editor(void)1078 char *get_editor(void)
1079 {
1080     return grace_editor;
1081 }
1082 
set_editor(const char * cmd)1083 void set_editor(const char *cmd)
1084 {
1085     strncpy(grace_editor, cmd, GR_MAXPATHLEN - 1);
1086 }
1087 
1088 static char help_viewer[GR_MAXPATHLEN] = GRACE_HELPVIEWER;
1089 
get_help_viewer(void)1090 char *get_help_viewer(void)
1091 {
1092     return help_viewer;
1093 }
1094 
set_help_viewer(const char * dir)1095 void set_help_viewer(const char *dir)
1096 {
1097     strncpy(help_viewer, dir, GR_MAXPATHLEN - 1);
1098 }
1099 
1100 /* project file name */
1101 static char docname[GR_MAXPATHLEN] = NONAME;
1102 
get_docname(void)1103 char *get_docname(void)
1104 {
1105     return docname;
1106 }
1107 
get_docbname(void)1108 char *get_docbname(void)
1109 {
1110     static char buf[GR_MAXPATHLEN];
1111     char *bufp;
1112 
1113     strcpy(buf, mybasename(docname));
1114     bufp = strrchr(buf, '.');
1115     if (bufp) {
1116         *(bufp) = '\0';
1117     }
1118 
1119     return buf;
1120 }
1121 
set_docname(const char * s)1122 void set_docname(const char *s)
1123 {
1124     if (s != NULL) {
1125         strncpy(docname, s, GR_MAXPATHLEN - 1);
1126     } else {
1127         strcpy(docname, NONAME);
1128     }
1129 }
1130 
1131 
errmsg(const char * buf)1132 void errmsg(const char *buf)
1133 {
1134 #ifdef NONE_GUI
1135     fprintf(stderr, "%s\n", buf);
1136 #else
1137     if (inwin) {
1138         errwin(buf);
1139     } else {
1140         fprintf(stderr, "%s\n", buf);
1141     }
1142 #endif
1143 }
1144 
yesnoterm(char * msg)1145 int yesnoterm(char *msg)
1146 {
1147     return 1;
1148 }
1149 
yesno(char * msg,char * s1,char * s2,char * help_anchor)1150 int yesno(char *msg, char *s1, char *s2, char *help_anchor)
1151 {
1152     if (noask) {
1153 	return 1;
1154     }
1155 #ifdef NONE_GUI
1156     return (yesnoterm(msg));
1157 #else
1158     if (inwin) {
1159         return (yesnowin(msg, s1, s2, help_anchor));
1160     } else {
1161         return (yesnoterm(msg));
1162     }
1163 #endif
1164 }
1165 
stufftext(char * s)1166 void stufftext(char *s)
1167 {
1168 #ifdef NONE_GUI
1169     printf(s);
1170 #else
1171     if (inwin) {
1172         stufftextwin(s);
1173     } else {
1174         printf(s);
1175     }
1176 #endif
1177     /* log results to file */
1178     if (resfp != NULL) {
1179 	fprintf(resfp, s);
1180     }
1181 }
1182 
1183 
mybasename(const char * s)1184 char *mybasename(const char *s)
1185 {
1186     int start, end;
1187     static char basename[GR_MAXPATHLEN];
1188 
1189     s = path_translate(s);
1190     if (s == NULL) {
1191         errmsg("Could not translate basename:");
1192         return "???";
1193     }
1194 
1195     end = strlen(s) - 1;
1196 
1197     /* root is a special case */
1198     if (end == 0 && *s == '/'){
1199         basename[0] = '/';
1200         return basename;
1201     }
1202 
1203     /* strip trailing white space and slashes */
1204     while (s[end] == '/' || s[end] == ' ' || s[end] == '\t') {
1205         end--;
1206     }
1207     /* find start of basename */
1208     start = end;
1209     do {
1210         start--;
1211     } while (start >= 0 && s[start] != '/');
1212 
1213     strncpy(basename, s + (start + 1), end - start);
1214     basename[end - start] = '\0';
1215     return basename;
1216 }
1217 
1218 static char workingdir[GR_MAXPATHLEN];
1219 
set_workingdir(const char * wd)1220 int set_workingdir(const char *wd)
1221 {
1222     char buf[GR_MAXPATHLEN];
1223 
1224     if (wd == NULL) {
1225         getcwd(workingdir, GR_MAXPATHLEN - 1);
1226         if (workingdir[strlen(workingdir)-1] != '/') {
1227             strcat(workingdir, "/");
1228         }
1229         return RETURN_SUCCESS;
1230     }
1231 
1232     strncpy(buf, wd, GR_MAXPATHLEN - 1);
1233     if (buf[0] == '~') {
1234         expand_tilde(buf);
1235     }
1236     if (chdir(buf) >= 0) {
1237         strncpy(workingdir, buf, GR_MAXPATHLEN - 1);
1238         if (workingdir[strlen(workingdir)-1] != '/') {
1239             strcat(workingdir, "/");
1240         }
1241 	return RETURN_SUCCESS;
1242     } else {
1243         return RETURN_FAILURE;
1244     }
1245 }
1246 
get_workingdir(void)1247 char *get_workingdir(void)
1248 {
1249     return workingdir;
1250 }
1251 
1252 static char *username = NULL;
1253 
init_username(void)1254 void init_username(void)
1255 {
1256     char *s;
1257 
1258 /*
1259  *     We don't use it for any kind of authentication, so why not let
1260  *     user to customize her name? :)
1261  */
1262     s = getenv("LOGNAME");
1263     if (s == NULL || s[0] == '\0') {
1264         s = getlogin();
1265         if (s == NULL || s[0] == '\0') {
1266             s = "a user";
1267         }
1268     }
1269     username = copy_string(username, s);
1270 }
1271 
get_username(void)1272 char *get_username(void)
1273 {
1274     return username;
1275 }
1276 
1277 static char *userhome = NULL;
1278 
init_userhome(void)1279 void init_userhome(void)
1280 {
1281     userhome = copy_string(NULL, getenv("HOME"));
1282     if (userhome == NULL || userhome[strlen(userhome) - 1] != '/') {
1283         userhome = concat_strings(userhome, "/");
1284     }
1285 }
1286 
get_userhome(void)1287 char *get_userhome(void)
1288 {
1289     return userhome;
1290 }
1291 
1292 /* TODO this needs some work */
expand_tilde(char * buf)1293 void expand_tilde(char *buf)
1294 {
1295     char buf2[GR_MAXPATHLEN];
1296 
1297     if (buf[0] == '~') {
1298 	if (strlen(buf) == 1) {
1299             strcpy(buf, get_userhome());
1300 	} else if (buf[1] == '/') {
1301             if (strlen(buf) > 2) {
1302                 strcpy(buf2, get_userhome());
1303 	        strcat(buf2, buf + 1);
1304 	        strcpy(buf, buf2);
1305             } else {
1306                 strcpy(buf, get_userhome());
1307             }
1308 	} else {
1309 	    char tmp[128], *pp = tmp, *q = buf + 1;
1310 	    struct passwd *pent;
1311 
1312 	    while (*q && (*q != '/')) {
1313 		*pp++ = *q++;
1314 	    }
1315 	    *pp = 0;
1316 	    if ((pent = getpwnam(tmp)) != NULL) {
1317 		strcpy(buf2, pent->pw_dir);
1318 		strcat(buf2, "/");
1319 		strcat(buf2, q);
1320 		strcpy(buf, buf2);
1321 	    } else {
1322 		errmsg("No user by that name");
1323 	    }
1324 	}
1325     }
1326 }
1327 
echomsg(char * msg)1328 void echomsg(char *msg)
1329 {
1330     if (inwin) {
1331 #ifndef NONE_GUI
1332         set_left_footer(msg);
1333 #endif
1334     } else {
1335         printf("%s\n", msg);
1336     }
1337 }
1338 
update_timestamp(void)1339 static void update_timestamp(void)
1340 {
1341     struct tm tm;
1342     time_t time_value;
1343     char *str;
1344 
1345     (void) time(&time_value);
1346     tm = *localtime(&time_value);
1347     str = asctime(&tm);
1348     if (str[strlen(str) - 1] == '\n') {
1349         str[strlen(str) - 1]= '\0';
1350     }
1351     set_plotstr_string(&timestamp, str);
1352 }
1353 
update_app_title(void)1354 void update_app_title(void)
1355 {
1356 #ifndef NONE_GUI
1357     set_title(mybasename(get_docname()));
1358 #endif
1359 }
1360 
1361 /*
1362  * dirtystate routines
1363  */
1364 
1365 static int dirtystate = 0;
1366 static int dirtystate_lock = FALSE;
1367 
set_dirtystate(void)1368 void set_dirtystate(void)
1369 {
1370     if (dirtystate_lock == FALSE) {
1371         dirtystate++;
1372         update_timestamp();
1373         update_app_title();
1374 
1375 /*
1376  * TODO:
1377  * 	if ( (dirtystate > SOME_LIMIT) ||
1378  *           (current_time - autosave_time > ANOTHER_LIMIT) ) {
1379  * 	    autosave();
1380  * 	}
1381  */
1382     }
1383 }
1384 
clear_dirtystate(void)1385 void clear_dirtystate(void)
1386 {
1387     dirtystate = 0;
1388     dirtystate_lock = FALSE;
1389     update_app_title();
1390 }
1391 
lock_dirtystate(flag)1392 void lock_dirtystate(flag)
1393 {
1394     dirtystate_lock = flag;
1395 }
1396 
is_dirtystate(void)1397 int is_dirtystate(void)
1398 {
1399     return (dirtystate ? TRUE:FALSE);
1400 }
1401 
system_wrap(const char * string)1402 int system_wrap(const char *string)
1403 {
1404     return system(string);
1405 }
1406 
msleep_wrap(unsigned int msec)1407 void msleep_wrap(unsigned int msec)
1408 {
1409     struct timeval timeout;
1410     timeout.tv_sec = msec / 1000;
1411     timeout.tv_usec = 1000 * (msec % 1000);
1412     select(0, NULL, NULL, NULL, &timeout);
1413 }
1414 
1415 #ifdef HAVE_SETLOCALE
1416 static int need_locale = FALSE;
1417 static char *system_locale_string, *posix_locale_string;
1418 
init_locale(void)1419 int init_locale(void)
1420 {
1421     char *s;
1422     s = setlocale(LC_NUMERIC, "");
1423     if (s == NULL) {
1424         /* invalid/unsupported locale */
1425         return RETURN_FAILURE;
1426     } else if (!strcmp(s, "C")) {
1427         /* don't enable need_locale, since the system locale is C */
1428         return RETURN_SUCCESS;
1429     } else {
1430         system_locale_string = copy_string(NULL, s);
1431         s = setlocale(LC_NUMERIC, "C");
1432         posix_locale_string = copy_string(NULL, s);
1433         need_locale = TRUE;
1434         return RETURN_SUCCESS;
1435     }
1436 }
1437 
set_locale_num(int flag)1438 void set_locale_num(int flag)
1439 {
1440     if (need_locale) {
1441         if (flag == TRUE) {
1442             setlocale(LC_NUMERIC, system_locale_string);
1443         } else {
1444             setlocale(LC_NUMERIC, posix_locale_string);
1445         }
1446     }
1447 }
1448 #else
init_locale(void)1449 int init_locale(void)
1450 {
1451     return RETURN_SUCCESS;
1452 }
1453 
set_locale_num(int flag)1454 void set_locale_num(int flag)
1455 {
1456 }
1457 #endif
1458 
1459 /*
1460  * Build info stuff
1461  */
bi_version_id(void)1462 long bi_version_id(void)
1463 {
1464     return BI_VERSION_ID;
1465 }
1466 
bi_version_string(void)1467 char *bi_version_string(void)
1468 {
1469     return BI_VERSION;
1470 }
1471 
bi_system(void)1472 char *bi_system(void)
1473 {
1474     return BI_SYSTEM;
1475 }
1476 
bi_date(void)1477 char *bi_date(void)
1478 {
1479     return BI_DATE;
1480 }
1481 
bi_gui(void)1482 char *bi_gui(void)
1483 {
1484     return BI_GUI;
1485 }
1486 
1487 #ifdef MOTIF_GUI
bi_gui_xbae(void)1488 char *bi_gui_xbae(void)
1489 {
1490     return BI_GUI_XBAE;
1491 }
1492 #endif
1493 
bi_t1lib(void)1494 char *bi_t1lib(void)
1495 {
1496     return BI_T1LIB;
1497 }
1498 
1499 #ifdef HAVE_LIBPNG
bi_pnglib(void)1500 char *bi_pnglib(void)
1501 {
1502     return BI_PNGLIB;
1503 }
1504 #endif
1505 
1506 #ifdef HAVE_LIBJPEG
bi_libjpeg(void)1507 char *bi_libjpeg(void)
1508 {
1509     return BI_LIBJPEG;
1510 }
1511 #endif
1512 
1513 #ifdef HAVE_LIBPDF
bi_libpdf(void)1514 char *bi_libpdf(void)
1515 {
1516     return BI_LIBPDF;
1517 }
1518 #endif
1519 
bi_ccompiler(void)1520 char *bi_ccompiler(void)
1521 {
1522     return BI_CCOMPILER;
1523 }
1524 
1525 #ifdef DEBUG
1526 static int debuglevel = 0;
1527 
set_debuglevel(int level)1528 void set_debuglevel(int level)
1529 {
1530     debuglevel = level;
1531 }
1532 
get_debuglevel(void)1533 int get_debuglevel(void)
1534 {
1535     return debuglevel;
1536 }
1537 #endif
1538 
1539