/* * Grace - GRaphing, Advanced Computation and Exploration of data * * Home page: http://plasma-gate.weizmann.ac.il/Grace/ * * Copyright (c) 1991-1995 Paul J Turner, Portland, OR * Copyright (c) 1996-2007 Grace Development Team * * Maintained by Evgeny Stambulchik * * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * misc utilities * */ #include #include #include #include #include #include #include #include #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include #include #ifdef HAVE_SYS_SELECT_H # include #endif #include #ifdef HAVE_SETLOCALE # include #endif #include "buildinfo.h" #include "globals.h" #include "utils.h" #include "files.h" #include "protos.h" static void rereadConfig(void); static RETSIGTYPE actOnSignal(int signo); static void bugwarn(char *signame); /* * free and check for NULL pointer */ void xfree(void *ptr) { if (ptr != NULL) { free(ptr); } } void *xmalloc(size_t size) { void *retval; if (size == 0) { retval = NULL; } else { retval = malloc(size); } if (retval == NULL && size != 0) { errmsg("Memory storage exceeded!"); } return retval; } void *xcalloc(size_t nmemb, size_t size) { void *retval; if (nmemb == 0) { retval = NULL; } else { retval = calloc(nmemb, size); } if (retval == NULL && nmemb != 0) { errmsg("Memory storage exceeded!"); } return retval; } void *xrealloc(void *ptr, size_t size) { void *retval; #if defined(REALLOC_IS_BUGGY) if (ptr == NULL) { retval = malloc(size); } else if (size == 0) { xfree(ptr); retval = NULL; } else { retval = realloc(ptr, size); } #else retval = realloc(ptr, size); if (size == 0) { retval = NULL; } #endif if (retval == NULL && size != 0) { errmsg("Memory storage exceeded!"); } return retval; } /* * swap doubles and ints */ void fswap(double *x, double *y) { double tmp; tmp = *x; *x = *y; *y = tmp; } void iswap(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; } int isoneof(int c, char *s) { while (*s) { if (c == *s) { return 1; } else { s++; } } return 0; } int argmatch(char *s1, char *s2, int atleast) { int l1 = strlen(s1); int l2 = strlen(s2); if (l1 < atleast) { return 0; } if (l1 > l2) { return 0; } return (strncmp(s1, s2, l1) == 0); } /* * convert a string from lower to upper case * leaving quoted strings alone */ void lowtoupper(char *s) { int i, quoteon = FALSE; for (i = 0; i < strlen(s); i++) { if (s[i] == '"') { if (!quoteon) { quoteon = TRUE; } else if ((i > 0) && (s[i-1] != '\\')) { quoteon = FALSE; } } if (quoteon == FALSE) { if (!isprint(s[i])) { s[i] = ' '; } else if (s[i] >= 'a' && s[i] <= 'z') { s[i] -= ' '; } } } } /* * remove all that fortran nastiness */ void convertchar(char *s) { while (*s++) { if (*s == ',') *s = ' '; if (*s == 'D' || *s == 'd') *s = 'e'; } } /* * log base 2 */ int ilog2(int n) { int i = 0; int n1 = n; while (n1 >>= 1) i++; if (1 << i != n) return -1; else return i; } /* * compute the area bounded by the polygon (xi,yi) */ double comp_area(int n, double *x, double *y) { int i; double sum = 0.0; for (i = 0; i < n; i++) { sum = sum + x[i] * y[(i + 1) % n] - y[i] * x[(i + 1) % n]; } return sum * 0.5; } /* * compute the perimeter bounded by the polygon (xi,yi) */ double comp_perimeter(int n, double *x, double *y) { int i; double sum = 0.0; for (i = 0; i < n - 1; i++) { sum = sum + hypot(x[i] - x[(i + 1) % n], y[i] - y[(i + 1) % n]); } return sum; } char *dayofweekstrs[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; char *dayofweekstrl[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; char *monthl[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; int dayofweek(double j) { int i = (int) floor(j + 1.5); return (i <= 0) ? 6 - (6 - i)%7 : i%7; } /* * escape quotes */ char *escapequotes (char *s) { static char *es = NULL; int i, k, n, len, elen; if (s == NULL) return NULL; len = strlen(s); es = xrealloc(es, (len + 1)*SIZEOF_CHAR); strcpy(es, s); n = 0; while ((es = strchr(es, '\"'))) { es++; n++; } elen = len + n + 1; es = xrealloc(es, elen*SIZEOF_CHAR); i = k = 0; while (i < len) { if (s[i] == '\"') { es[k] = '\\'; k++; } es[k] = s[i]; i++; k++; } es[elen-1] = '\0'; return es; } int sign(double a) { if (a > 0.0) { return +1; } else if (a < 0.0) { return -1; } else { return 0; } } double mytrunc(double a) { if (a > 0.0) { return floor(a); } else { return ceil(a); } } /* * exit grace */ void bailout(void) { if (!is_dirtystate() || yesno("Exit losing unsaved changes?", NULL, NULL, NULL)) { if (resfp) { grace_close(resfp); } exit(0); } } /* * Reread config (TODO) */ static void rereadConfig(void) { getparms("gracerc"); } static void please_report_the_bug(void) { fprintf(stderr, "\nPlease use \"Help/Comments\" to report the bug.\n"); #ifdef HAVE_LESSTIF fprintf(stderr, "NB. This version of Grace was compiled with LessTif.\n"); fprintf(stderr, " Make sure to read the FAQ carefully prior to\n"); fprintf(stderr, " reporting the bug, ESPECIALLY is the problem might\n"); fprintf(stderr, " be related to the graphical interface.\n"); #endif } /* * Warn about bug (TODO X message) */ static void bugwarn(char *signame) { static int emergency_save = FALSE; /* * Since we got so far, memory is probably corrupted so it's better to use * a static storage */ static char buf[GR_MAXPATHLEN]; /* number of interrupts received during the emergency save */ static int interrupts; if (emergency_save != FALSE) { /* don't mind signals anymore: we're in emergency save mode already */ interrupts++; if (interrupts > 10) { fprintf(stderr, "oh, no luck :-(\n"); please_report_the_bug(); abort(); } return; } else { emergency_save = TRUE; interrupts = 0; fprintf(stderr, "\a\nOops! Got %s\n", signame); if (is_dirtystate()) { strcpy(buf, get_docname()); strcat(buf, "$"); fprintf(stderr, "Trying to save your work into file \"%s\"... ", buf); fflush(stderr); noask = TRUE; if (save_project(buf) == RETURN_SUCCESS) { fprintf(stderr, "ok!\n"); } else { fprintf(stderr, "oh, no luck :-(\n"); } } please_report_the_bug(); abort(); } } /* * Signal-handling routines */ static RETSIGTYPE actOnSignal(int signo) { char signame[16]; installSignal(); switch (signo) { #ifdef SIGHUP case SIGHUP: rereadConfig(); break; #endif #ifdef SIGINT case SIGINT: #endif #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGTERM case SIGTERM: #endif bailout(); break; #ifdef SIGILL case SIGILL: strcpy(signame, "SIGILL"); #endif #ifdef SIGFPE case SIGFPE: strcpy(signame, "SIGFPE"); #endif #ifdef SIGBUS case SIGBUS: strcpy(signame, "SIGBUS"); #endif #ifdef SIGSEGV case SIGSEGV: strcpy(signame, "SIGSEGV"); #endif #ifdef SIGSYS case SIGSYS: strcpy(signame, "SIGSYS"); #endif bugwarn(signame); break; default: break; } } void installSignal(void){ #ifdef SIGHUP signal(SIGHUP, actOnSignal); /* hangup */ #endif #ifdef SIGINT signal(SIGINT, actOnSignal); /* interrupt */ #endif #ifdef SIGQUIT signal(SIGQUIT, actOnSignal); /* quit */ #endif #ifdef SIGILL signal(SIGILL, actOnSignal); /* illegal instruction */ #endif #ifdef SIGFPE signal(SIGFPE, actOnSignal); /* floating point exception */ #endif #ifdef SIGBUS signal(SIGBUS, actOnSignal); /* bus error */ #endif #ifdef SIGSEGV signal(SIGSEGV, actOnSignal); /* segmentation violation */ #endif #ifdef SIGSYS signal(SIGSYS, actOnSignal); /* bad argument to system call */ #endif #ifdef SIGTERM signal(SIGTERM, actOnSignal); /* software termination signal */ #endif #ifdef SIGALRM signal(SIGALRM, actOnSignal); /* timer */ #endif #ifdef SIGIO signal(SIGIO, actOnSignal); /* input/output ready */ #endif } /* create format string */ char *create_fstring(int form, int prec, double loc, int type) { char format[64], *eng_prefix,*comp_prefix; static char s[MAX_STRING_LENGTH]; double tmp; int m, d, y, h, mm, sec; double arcmin, arcsec; int exponent; double mantissa; int yprec; if (two_digits_years_allowed()) { yprec = 2; } else { yprec = 4; } /* for locale decimal points */ set_locale_num(TRUE); strcpy(format, "%.*lf"); switch (form) { case FORMAT_DECIMAL: sprintf(s, format, prec, loc); tmp = atof(s); /* fix reverse axes problem when loc == -0.0 */ if (tmp == 0.0) { strcpy(format, "%.*lf"); loc = 0.0; sprintf(s, format, prec, loc); } break; case FORMAT_EXPONENTIAL: strcpy(format, "%.*le"); sprintf(s, format, prec, loc); tmp = atof(s); /* fix reverse axes problem when loc == -0.0 */ if (tmp == 0.0) { strcpy(format, "%.*le"); loc = 0.0; sprintf(s, format, prec, loc); } break; case FORMAT_SCIENTIFIC: if (loc != 0.0) { exponent = (int) floor(log10(fabs(loc))); mantissa = loc/pow(10.0, (double) exponent); if (type == LFORMAT_TYPE_EXTENDED) { strcpy(format, "%.*f\\x\\c4\\C\\f{}10\\S%d\\N"); } else { strcpy(format, "%.*fx10(%d)"); } sprintf(s, format, prec, mantissa, exponent); } else { strcpy(format, "%.*f"); sprintf(s, format, prec, 0.0); } break; case FORMAT_COMPUTING: /* As per FORMAT_GENERAL but uses computer notation (K,M,G,...) * to give the value in multiples of the powers of 1024 */ if (loc != 0.0) { exponent = (int) floor(log2(fabs(loc))); if (exponent < 10) { exponent = 0; } else if (exponent > 80) { exponent = 80; } else { exponent = (int) floor((double) exponent/10)*10; } } else { exponent = 0; } /* use next prefix if we would get 1024 because ** of the print precision requested. This happens ** for values slightly less than 1024. */ sprintf(s, "%.*g", prec, loc/(pow(2.0, exponent))); if ((exponent < 80) && (strcmp(s, "1024") == 0)){ exponent += 10; } switch (exponent) { case 10: /* kilo */ comp_prefix = "K"; break; case 20: /* Mega */ comp_prefix = "M"; break; case 30: /* Giga */ comp_prefix = "G"; break; case 40: /* Tera */ comp_prefix = "T"; break; case 50: /* Peta */ comp_prefix = "P"; break; case 60: /* Exa */ comp_prefix = "E"; break; case 70: /* Zetta */ comp_prefix = "Z"; break; case 80: /* Yotta */ comp_prefix = "Y"; break; default: comp_prefix = ""; break; } sprintf(s,"%.*g%s", prec, loc/(pow(2.0, exponent)), comp_prefix); tmp = atof(s); /* fix reverse axes problem when loc == -0.0 */ if (tmp == 0.0) { strcpy(format, "%lg"); loc = 0.0; sprintf(s, format, loc); } break; case FORMAT_ENGINEERING: if (loc != 0.0) { exponent = (int) floor(log10(fabs(loc))); if (exponent < -24) { exponent = -24; } else if (exponent > 24) { exponent = 24; } else { exponent = (int) floor((double) exponent/3)*3; } } else { exponent = 0; } switch (exponent) { case -24: /* yocto */ eng_prefix = "y"; break; case -21: /* zepto */ eng_prefix = "z"; break; case -18: /* atto */ eng_prefix = "a"; break; case -15: /* fempto */ eng_prefix = "f"; break; case -12: /* pico */ eng_prefix = "p"; break; case -9: /* nano */ eng_prefix = "n"; break; case -6: /* micro */ if (type == LFORMAT_TYPE_EXTENDED) { eng_prefix = "\\xm\\f{}"; } else { eng_prefix = "mk"; } break; case -3: /* milli */ eng_prefix = "m"; break; case 3: /* kilo */ eng_prefix = "k"; break; case 6: /* Mega */ eng_prefix = "M"; break; case 9: /* Giga */ eng_prefix = "G"; break; case 12: /* Tera */ eng_prefix = "T"; break; case 15: /* Peta */ eng_prefix = "P"; break; case 18: /* Exa */ eng_prefix = "E"; break; case 21: /* Zetta */ eng_prefix = "Z"; break; case 24: /* Yotta */ eng_prefix = "Y"; break; default: eng_prefix = ""; break; } strcpy(format, "%.*f %s"); sprintf(s, format, prec, loc/(pow(10.0, exponent)), eng_prefix); break; case FORMAT_POWER: if (loc < 0.0) { loc = log10(-loc); if (type == LFORMAT_TYPE_EXTENDED) { strcpy(format, "-10\\S%.*lf\\N"); } else { strcpy(format, "-10(%.*lf)\\N"); } } else if (loc == 0.0) { sprintf(format, "%.*f", prec, 0.0); } else { loc = log10(loc); if (type == LFORMAT_TYPE_EXTENDED) { strcpy(format, "10\\S%.*lf\\N"); } else { strcpy(format, "10(%.*lf)\\N"); } } sprintf(s, format, prec, loc); break; case FORMAT_GENERAL: strcpy(format, "%.*lg"); sprintf(s, format, prec, loc); tmp = atof(s); if (tmp == 0.0) { strcpy(format, "%lg"); loc = 0.0; sprintf(s, format, loc); } break; case FORMAT_DDMMYY: strcpy(format, "%02d-%02d-%0*d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, d, m, yprec, y); break; case FORMAT_MMDDYY: strcpy(format, "%02d-%02d-%0*d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, m, d, yprec, y); break; case FORMAT_YYMMDD: strcpy(format, "%0*d-%02d-%02d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, yprec, y, m, d); break; case FORMAT_MMYY: strcpy(format, "%02d-%0*d"); jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, m, yprec, y); break; case FORMAT_MMDD: strcpy(format, "%02d-%02d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, m, d); break; case FORMAT_MONTHDAY: strcpy(format, "%s-%02d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); if (m - 1 < 0 || m - 1 > 11) { sprintf(s, format, "???"); } else { sprintf(s, format, months[m - 1], d); } break; case FORMAT_DAYMONTH: strcpy(format, "%02d-%s"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); if (m - 1 < 0 || m - 1 > 11) { sprintf(s, format, "???"); } else { sprintf(s, format, d, months[m - 1]); } break; case FORMAT_MONTHS: strcpy(format, "%s"); jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec); if (m - 1 < 0 || m - 1 > 11) { sprintf(s, format, "???"); } else { sprintf(s, format, months[m - 1]); } break; case FORMAT_MONTHSY: strcpy(format, "%s-%0*d"); jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec); if (m - 1 < 0 || m - 1 > 11) { sprintf(s, format, "???"); } else { sprintf(s, format, months[m - 1], yprec, y); } break; case FORMAT_MONTHL: strcpy(format, "%s"); jul_to_cal_and_time(loc, ROUND_MONTH, &y, &m, &d, &h, &mm, &sec); if (m - 1 < 0 || m - 1 > 11) { sprintf(s, format, "???"); } else { sprintf(s, format, monthl[m - 1]); } break; case FORMAT_DAYOFWEEKS: strcpy(format, "%s"); sprintf(s, format, dayofweekstrs[dayofweek(loc + get_ref_date())]); break; case FORMAT_DAYOFWEEKL: strcpy(format, "%s"); sprintf(s, format, dayofweekstrl[dayofweek(loc + get_ref_date())]); break; case FORMAT_DAYOFYEAR: strcpy(format, "%d"); jul_to_cal_and_time(loc, ROUND_DAY, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, 1 + (int) (cal_to_jul(y, m, d) - cal_to_jul(y, 1, 1))); break; case FORMAT_HMS: strcpy(format, "%02d:%02d:%02d"); jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, h, mm, sec); break; case FORMAT_MMDDHMS: strcpy(format, "%02d-%02d %02d:%02d:%02d"); jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, m, d, h, mm, sec); break; case FORMAT_MMDDYYHMS: strcpy(format, "%02d-%02d-%d %02d:%02d:%02d"); jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, m, d, y, h, mm, sec); break; case FORMAT_YYMMDDHMS: strcpy(format, "%0*d-%02d-%02d %02d:%02d:%02d"); jul_to_cal_and_time(loc, ROUND_SECOND, &y, &m, &d, &h, &mm, &sec); sprintf(s, format, yprec, y, m, d, h, mm, sec); break; case FORMAT_DEGREESLON: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%.*lfW"); } else if (loc > 0.0) { strcpy(format, "%.*lfE"); } else { strcpy(format, "0"); } sprintf(s, format, prec, loc); break; case FORMAT_DEGREESMMLON: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d %.*lf' W"); } else if (loc > 0.0) { strcpy(format, "%d %.*lf' E"); } else { strcpy(format, "0 0'"); } y = loc; arcmin = (loc - y) * 60.0; sprintf(s, format, y, prec, arcmin); break; case FORMAT_DEGREESMMSSLON: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d %d' %.*lf\" W"); } else if (loc > 0.0) { strcpy(format, "%d %d' %.*lf\" E"); } else { strcpy(format, "0 0' 0\""); } y = loc; arcsec = (loc - y) * 3600.0; m = arcsec / 60.0; arcsec = (arcsec - m * 60); sprintf(s, format, y, m, prec, arcsec); break; case FORMAT_MMSSLON: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d' %.*lf\" W"); } else if (loc > 0.0) { strcpy(format, "%d' %.*lf\" E"); } else { strcpy(format, "0 0' 0\""); } y = loc; arcsec = (loc - y) * 3600.0; m = arcsec / 60.0; arcsec = (arcsec - m * 60); sprintf(s, format, m, prec, arcsec); break; case FORMAT_DEGREESLAT: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%.*lfS"); } else if (loc > 0.0) { strcpy(format, "%.*lfN"); } else { strcpy(format, "0"); } sprintf(s, format, prec, loc); break; case FORMAT_DEGREESMMLAT: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d %.*lf' S"); } else if (loc > 0.0) { strcpy(format, "%d %.*lf' N"); } else { strcpy(format, "0 0'"); } y = loc; arcsec = (loc - y) * 60.0; sprintf(s, format, y, prec, arcsec); break; case FORMAT_DEGREESMMSSLAT: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d %d' %.*lf\" S"); } else if (loc > 0.0) { strcpy(format, "%d %d' %.*lf\" N"); } else { strcpy(format, "0 0' 0\""); } y = loc; arcsec = (loc - y) * 3600.0; m = arcsec / 60.0; arcsec = (arcsec - m * 60); sprintf(s, format, y, m, prec, arcsec); break; case FORMAT_MMSSLAT: if (loc < 0.0) { loc *= -1.0; strcpy(format, "%d' %.*lf\" S"); } else if (loc > 0.0) { strcpy(format, "%d' %.*lf\" N"); } else { strcpy(format, "0 0' 0\""); } y = loc; arcsec = (loc - y) * 3600.0; m = arcsec / 60.0; arcsec = (arcsec - m * 60); sprintf(s, format, m, prec, arcsec); break; default: sprintf(s, format, prec, loc); break; } /* revert to POSIX */ set_locale_num(FALSE); return(s); } int bin_dump(char *value, int i, int pad) { char *word; if (i > pad - 1) { return 0; } word = value; #ifdef WORDS_BIGENDIAN return (((*word)>>i)&0x01); #else switch (pad) { case 8: return (((*word)>>i)&0x01); break; case 16: if (i < 8) { word++; return (((*word)>>i)&0x01); } else { return (((*word)>>(8 - i))&0x01); } break; case 32: if (i < 8) { word += 2; return (((*word)>>i)&0x01); } else if (i < 16) { word++; return (((*word)>>(8 - i))&0x01); } else { return (((*word)>>(16 - i))&0x01); } break; default: return 0; } #endif } unsigned char reversebits(unsigned char inword) { int i; unsigned char result = 0; for (i = 0; i <= 7; i++) { result |= (((inword)>>i)&0x01)<<(7 - i); } return (result); } char *copy_string(char *dest, const char *src) { if (src == dest) { ; } else if (src == NULL) { xfree(dest); dest = NULL; } else { dest = xrealloc(dest, (strlen(src) + 1)*SIZEOF_CHAR); strcpy(dest, src); } return(dest); } char *concat_strings(char *dest, const char *src) { if (src != NULL) { if (dest == NULL) { dest = copy_string(NULL, src); } else { dest = xrealloc(dest, (strlen(dest) + strlen(src) + 1)*SIZEOF_CHAR); if (dest != NULL) { strcat(dest, src); } } } return(dest); } int compare_strings(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) { return TRUE; } else if (s1 == NULL || s2 == NULL) { return FALSE; } else { return (strcmp(s1, s2) == 0); } } /* location of Grace home directory */ static char grace_home[GR_MAXPATHLEN] = GRACE_HOME; char *get_grace_home(void) { return grace_home; } void set_grace_home(const char *dir) { strncpy(grace_home, dir, GR_MAXPATHLEN - 1); } /* print command */ static char print_cmd[GR_MAXPATHLEN] = GRACE_PRINT_CMD; char *get_print_cmd(void) { return print_cmd; } void set_print_cmd(const char *cmd) { strncpy(print_cmd, cmd, GR_MAXPATHLEN - 1); } /* editor */ static char grace_editor[GR_MAXPATHLEN] = GRACE_EDITOR; char *get_editor(void) { return grace_editor; } void set_editor(const char *cmd) { strncpy(grace_editor, cmd, GR_MAXPATHLEN - 1); } static char help_viewer[GR_MAXPATHLEN] = GRACE_HELPVIEWER; char *get_help_viewer(void) { return help_viewer; } void set_help_viewer(const char *dir) { strncpy(help_viewer, dir, GR_MAXPATHLEN - 1); } /* project file name */ static char docname[GR_MAXPATHLEN] = NONAME; char *get_docname(void) { return docname; } char *get_docbname(void) { static char buf[GR_MAXPATHLEN]; char *bufp; strcpy(buf, mybasename(docname)); bufp = strrchr(buf, '.'); if (bufp) { *(bufp) = '\0'; } return buf; } void set_docname(const char *s) { if (s != NULL) { strncpy(docname, s, GR_MAXPATHLEN - 1); } else { strcpy(docname, NONAME); } } void errmsg(const char *buf) { #ifdef NONE_GUI fprintf(stderr, "%s\n", buf); #else if (inwin) { errwin(buf); } else { fprintf(stderr, "%s\n", buf); } #endif } int yesnoterm(char *msg) { return 1; } int yesno(char *msg, char *s1, char *s2, char *help_anchor) { if (noask) { return 1; } #ifdef NONE_GUI return (yesnoterm(msg)); #else if (inwin) { return (yesnowin(msg, s1, s2, help_anchor)); } else { return (yesnoterm(msg)); } #endif } void stufftext(char *s) { #ifdef NONE_GUI printf(s); #else if (inwin) { stufftextwin(s); } else { printf(s); } #endif /* log results to file */ if (resfp != NULL) { fprintf(resfp, s); } } char *mybasename(const char *s) { int start, end; static char basename[GR_MAXPATHLEN]; s = path_translate(s); if (s == NULL) { errmsg("Could not translate basename:"); return "???"; } end = strlen(s) - 1; /* root is a special case */ if (end == 0 && *s == '/'){ basename[0] = '/'; return basename; } /* strip trailing white space and slashes */ while (s[end] == '/' || s[end] == ' ' || s[end] == '\t') { end--; } /* find start of basename */ start = end; do { start--; } while (start >= 0 && s[start] != '/'); strncpy(basename, s + (start + 1), end - start); basename[end - start] = '\0'; return basename; } static char workingdir[GR_MAXPATHLEN]; int set_workingdir(const char *wd) { char buf[GR_MAXPATHLEN]; if (wd == NULL) { getcwd(workingdir, GR_MAXPATHLEN - 1); if (workingdir[strlen(workingdir)-1] != '/') { strcat(workingdir, "/"); } return RETURN_SUCCESS; } strncpy(buf, wd, GR_MAXPATHLEN - 1); if (buf[0] == '~') { expand_tilde(buf); } if (chdir(buf) >= 0) { strncpy(workingdir, buf, GR_MAXPATHLEN - 1); if (workingdir[strlen(workingdir)-1] != '/') { strcat(workingdir, "/"); } return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } char *get_workingdir(void) { return workingdir; } static char *username = NULL; void init_username(void) { char *s; /* * We don't use it for any kind of authentication, so why not let * user to customize her name? :) */ s = getenv("LOGNAME"); if (s == NULL || s[0] == '\0') { s = getlogin(); if (s == NULL || s[0] == '\0') { s = "a user"; } } username = copy_string(username, s); } char *get_username(void) { return username; } static char *userhome = NULL; void init_userhome(void) { userhome = copy_string(NULL, getenv("HOME")); if (userhome == NULL || userhome[strlen(userhome) - 1] != '/') { userhome = concat_strings(userhome, "/"); } } char *get_userhome(void) { return userhome; } /* TODO this needs some work */ void expand_tilde(char *buf) { char buf2[GR_MAXPATHLEN]; if (buf[0] == '~') { if (strlen(buf) == 1) { strcpy(buf, get_userhome()); } else if (buf[1] == '/') { if (strlen(buf) > 2) { strcpy(buf2, get_userhome()); strcat(buf2, buf + 1); strcpy(buf, buf2); } else { strcpy(buf, get_userhome()); } } else { char tmp[128], *pp = tmp, *q = buf + 1; struct passwd *pent; while (*q && (*q != '/')) { *pp++ = *q++; } *pp = 0; if ((pent = getpwnam(tmp)) != NULL) { strcpy(buf2, pent->pw_dir); strcat(buf2, "/"); strcat(buf2, q); strcpy(buf, buf2); } else { errmsg("No user by that name"); } } } } void echomsg(char *msg) { if (inwin) { #ifndef NONE_GUI set_left_footer(msg); #endif } else { printf("%s\n", msg); } } static void update_timestamp(void) { struct tm tm; time_t time_value; char *str; (void) time(&time_value); tm = *localtime(&time_value); str = asctime(&tm); if (str[strlen(str) - 1] == '\n') { str[strlen(str) - 1]= '\0'; } set_plotstr_string(×tamp, str); } void update_app_title(void) { #ifndef NONE_GUI set_title(mybasename(get_docname())); #endif } /* * dirtystate routines */ static int dirtystate = 0; static int dirtystate_lock = FALSE; void set_dirtystate(void) { if (dirtystate_lock == FALSE) { dirtystate++; update_timestamp(); update_app_title(); /* * TODO: * if ( (dirtystate > SOME_LIMIT) || * (current_time - autosave_time > ANOTHER_LIMIT) ) { * autosave(); * } */ } } void clear_dirtystate(void) { dirtystate = 0; dirtystate_lock = FALSE; update_app_title(); } void lock_dirtystate(flag) { dirtystate_lock = flag; } int is_dirtystate(void) { return (dirtystate ? TRUE:FALSE); } int system_wrap(const char *string) { return system(string); } void msleep_wrap(unsigned int msec) { struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = 1000 * (msec % 1000); select(0, NULL, NULL, NULL, &timeout); } #ifdef HAVE_SETLOCALE static int need_locale = FALSE; static char *system_locale_string, *posix_locale_string; int init_locale(void) { char *s; s = setlocale(LC_NUMERIC, ""); if (s == NULL) { /* invalid/unsupported locale */ return RETURN_FAILURE; } else if (!strcmp(s, "C")) { /* don't enable need_locale, since the system locale is C */ return RETURN_SUCCESS; } else { system_locale_string = copy_string(NULL, s); s = setlocale(LC_NUMERIC, "C"); posix_locale_string = copy_string(NULL, s); need_locale = TRUE; return RETURN_SUCCESS; } } void set_locale_num(int flag) { if (need_locale) { if (flag == TRUE) { setlocale(LC_NUMERIC, system_locale_string); } else { setlocale(LC_NUMERIC, posix_locale_string); } } } #else int init_locale(void) { return RETURN_SUCCESS; } void set_locale_num(int flag) { } #endif /* * Build info stuff */ long bi_version_id(void) { return BI_VERSION_ID; } char *bi_version_string(void) { return BI_VERSION; } char *bi_system(void) { return BI_SYSTEM; } char *bi_date(void) { return BI_DATE; } char *bi_gui(void) { return BI_GUI; } #ifdef MOTIF_GUI char *bi_gui_xbae(void) { return BI_GUI_XBAE; } #endif char *bi_t1lib(void) { return BI_T1LIB; } #ifdef HAVE_LIBPNG char *bi_pnglib(void) { return BI_PNGLIB; } #endif #ifdef HAVE_LIBJPEG char *bi_libjpeg(void) { return BI_LIBJPEG; } #endif #ifdef HAVE_LIBPDF char *bi_libpdf(void) { return BI_LIBPDF; } #endif char *bi_ccompiler(void) { return BI_CCOMPILER; } #ifdef DEBUG static int debuglevel = 0; void set_debuglevel(int level) { debuglevel = level; } int get_debuglevel(void) { return debuglevel; } #endif