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(×tamp, 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