2 static char *RCSid() { return RCSid("$Id: util.c,v 1.65.2.9 2009/02/05 17:17:25 sfeam Exp $"); }
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
41 #include "datafile.h" /* for df_showdata and df_reset_after_error */
44 /* #include "setshow.h" */ /* for month names etc */
45 #include "term_api.h" /* for term_end_plot() used by graph_error() */
47 #if defined(HAVE_DIRENT_H)
48 # include <sys/types.h>
50 #elif defined(_Windows)
54 #if defined(HAVE_PWD_H)
55 # include <sys/types.h>
57 #elif defined(_Windows)
59 # if !defined(INFO_BUFFER_SIZE)
60 # define INFO_BUFFER_SIZE 32767
64 /* Exported (set-table) variables */
67 char *decimalsign = NULL;
69 const char *current_prompt = NULL; /* to be set by read_line() */
71 /* internal prototypes */
73 static void mant_exp __PROTO((double, double, TBOOLEAN, double *, int *, const char *));
74 static void parse_sq __PROTO((char *));
78 * chr_in_str() compares the characters in the string of token number t_num
79 * with c, and returns TRUE if a match was found.
82 chr_in_str(int t_num, int c)
86 if (!token[t_num].is_token)
87 return (FALSE); /* must be a value--can't be equal */
88 for (i = 0; i < token[t_num].length; i++) {
89 if (input_line[token[t_num].start_index + i] == c)
97 * equals() compares string value of token number t_num with str[], and
98 * returns TRUE if they are identical.
101 equals(int t_num, const char *str)
105 if (!token[t_num].is_token)
106 return (FALSE); /* must be a value--can't be equal */
107 for (i = 0; i < token[t_num].length; i++) {
108 if (gp_input_line[token[t_num].start_index + i] != str[i])
111 /* now return TRUE if at end of str[], FALSE if not */
112 return (str[i] == NUL);
118 * almost_equals() compares string value of token number t_num with str[], and
119 * returns TRUE if they are identical up to the first $ in str[].
122 almost_equals(int t_num, const char *str)
126 int start = token[t_num].start_index;
127 int length = token[t_num].length;
131 if (!token[t_num].is_token)
132 return FALSE; /* must be a value--can't be equal */
133 for (i = 0; i < length + after; i++) {
134 if (str[i] != gp_input_line[start + i]) {
139 start--; /* back up token ptr */
144 /* i now beyond end of token string */
146 return (after || str[i] == '$' || str[i] == NUL);
155 return (token[t_num].is_token &&
156 (gp_input_line[token[t_num].start_index] == '\'' ||
157 gp_input_line[token[t_num].start_index] == '"'));
160 /* Test for the existence of a variable without triggering errors.
162 * 0 variable does not exist or is not defined
163 * >0 type of variable: INTGR, CMPLX, STRING
168 struct udvt_entry **udv_ptr = &first_udv;
171 if (equals(t_num, (*udv_ptr)->udv_name)) {
172 if ((*udv_ptr)->udv_undef)
175 return (*udv_ptr)->udv_value.type;
177 udv_ptr = &((*udv_ptr)->next_udv);
185 return (!token[t_num].is_token);
192 return (token[t_num].is_token &&
193 ((isalpha((unsigned char) gp_input_line[token[t_num].start_index])) ||
194 (gp_input_line[token[t_num].start_index] == '_')));
199 * is_definition() returns TRUE if the next tokens are of the form
202 * identifier ( identifer {,identifier} ) =
205 is_definition(int t_num)
208 if (isletter(t_num) && equals(t_num + 1, "="))
212 /* look for dummy variables */
213 if (isletter(t_num) && equals(t_num + 1, "(") && isletter(t_num + 2)) {
214 t_num += 3; /* point past first dummy */
215 while (equals(t_num, ",")) {
216 if (!isletter(++t_num))
220 return (equals(t_num, ")") && equals(t_num + 1, "="));
229 * copy_str() copies the string in token number t_num into str, appending
230 * a null. No more than max chars are copied (including \0).
233 copy_str(char *str, int t_num, int max)
236 int start = token[t_num].start_index;
237 int count = token[t_num].length;
241 FPRINTF((stderr, "str buffer overflow in copy_str"));
245 str[i++] = gp_input_line[start++];
246 } while (i != count);
251 /* length of token string */
255 return (size_t)(token[t_num].length);
259 * quote_str() does the same thing as copy_str, except it ignores the
260 * quotes at both ends. This seems redundant, but is done for
264 quote_str(char *str, int t_num, int max)
267 int start = token[t_num].start_index + 1;
270 if ((count = token[t_num].length - 2) >= max) {
272 FPRINTF((stderr, "str buffer overflow in quote_str"));
276 str[i++] = gp_input_line[start++];
277 } while (i != count);
280 /* convert \t and \nnn (octal) to char if in double quotes */
281 if (gp_input_line[token[t_num].start_index] == '"')
289 * capture() copies into str[] the part of gp_input_line[] which lies between
290 * the begining of token[start] and end of token[end].
293 capture(char *str, int start, int end, int max)
297 e = token[end].start_index + token[end].length;
298 if (e - token[start].start_index >= max) {
299 e = token[start].start_index + max - 1;
300 FPRINTF((stderr, "str buffer overflow in capture"));
302 for (i = token[start].start_index; i < e && gp_input_line[i] != NUL; i++)
303 *str++ = gp_input_line[i];
309 * m_capture() is similar to capture(), but it mallocs storage for the
313 m_capture(char **str, int start, int end)
318 e = token[end].start_index + token[end].length;
319 *str = gp_realloc(*str, (e - token[start].start_index + 1), "string");
321 for (i = token[start].start_index; i < e && gp_input_line[i] != NUL; i++)
322 *s++ = gp_input_line[i];
328 * m_quote_capture() is similar to m_capture(), but it removes
329 * quotes from either end of the string.
332 m_quote_capture(char **str, int start, int end)
337 e = token[end].start_index + token[end].length - 1;
338 *str = gp_realloc(*str, (e - token[start].start_index + 1), "string");
340 for (i = token[start].start_index + 1; i < e && gp_input_line[i] != NUL; i++)
341 *s++ = gp_input_line[i];
344 if (gp_input_line[token[start].start_index] == '"')
352 * Wrapper for isstring + m_quote_capture that can be used with
353 * or without GP_STRING_VARS enabled.
359 char *newstring = NULL;
361 #ifdef GP_STRING_VARS
363 int save_token = c_token;
366 const_string_express(&a);
367 if (a.type == STRING)
368 newstring = a.v.string_val;
370 c_token = save_token;
372 if (!END_OF_COMMAND && isstring(c_token)) {
373 m_quote_capture(&newstring, c_token, c_token);
382 /* Our own version of strdup()
383 * Make copy of string into gp_alloc'd memory
384 * As with all conforming str*() functions,
385 * it is the caller's responsibility to pass
389 gp_strdup(const char *s)
397 d = gp_alloc(strlen(s) + 1, "gp_strdup");
399 memcpy (d, s, strlen(s) + 1);
407 * Allocate a new string and initialize it by concatenating two
411 gp_stradd(const char *a, const char *b)
413 char *new = gp_alloc(strlen(a)+strlen(b)+1,"gp_stradd");
419 /* HBB 20020405: moved these functions here from axis.c, where they no
420 * longer truly belong. */
421 /*{{{ mant_exp - split into mantissa and/or exponent */
422 /* HBB 20010121: added code that attempts to fix rounding-induced
423 * off-by-one errors in 10^%T and similar output formats */
428 TBOOLEAN scientific, /* round to power of 3 */
429 double *m, /* results */
431 const char *format) /* format string for fixup */
454 l10 = log10(x) / log10_base;
456 mantissa = pow(10.0, log10_base * (l10 - power));
458 /* round power to an integer multiple of 3, to get what's
459 * sometimes called 'scientific' or 'engineering' notation. Also
460 * useful for handling metric unit prefixes like 'kilo' or 'micro'
463 /* Scientific mode makes no sense whatsoever if the base of
464 * the logarithmic axis is anything but 10.0 */
465 assert(log10_base == 1.0);
467 /* HBB FIXED 20040701: negative modulo positive may yield
468 * negative result. But we always want an effectively
469 * positive modulus --> adjust input by one step */
484 int_error (NO_CARET, "Internal error in scientific number formatting");
486 power -= (power % 3);
489 /* HBB 20010121: new code for decimal mantissa fixups. Looks at
490 * format string to see how many decimals will be put there. Iff
491 * the number is so close to an exact power of 10 that it will be
492 * rounded up to 10.0e??? by an sprintf() with that many digits of
493 * precision, increase the power by 1 to get a mantissa in the
494 * region of 1.0. If this handling is not wanted, pass NULL as
495 * the format string */
496 /* HBB 20040521: extended to also work for bases other than 10.0 */
498 double actual_base = (scientific ? 1000 : pow(10.0, log10_base));
502 format = strchr (format, '.');
504 /* a decimal point was found in the format, so use that
506 precision = strtol(format + 1, NULL, 10);
508 /* See if mantissa would be right on the border. The
509 * condition to watch out for is that the mantissa is within
510 * one printing precision of the next power of the logarithm
511 * base. So add the 0.5*10^-precision to the mantissa, and
512 * see if it's now larger than the base of the scale */
513 tolerance = pow(10.0, -precision) / 2;
514 if (mantissa + tolerance >= actual_base) {
515 mantissa /= actual_base;
516 power += (scientific ? 3 : 1);
520 *m = sign * mantissa;
529 * Workaround until we have a better solution ...
530 * Note: this assumes that all calls to sprintf in gprintf have
531 * exactly three args. Lars
534 # define sprintf(str,fmt,arg) \
535 if (snprintf((str),count,(fmt),(arg)) > count) \
536 fprintf (stderr,"%s:%d: Warning: too many digits for format\n",__FILE__,__LINE__)
540 /* extended s(n)printf */
541 /* HBB 20010121: added code to maintain consistency between mantissa
542 * and exponent across sprintf() calls. The problem: format string
543 * '%t*10^%T' will display 9.99 as '10.0*10^0', but 10.01 as
544 * '1.0*10^1'. This causes problems for people using the %T part,
545 * only, with logscaled axes, in combination with the occasional
546 * round-off error. */
555 char temp[MAX_LINE_LEN + 1];
557 TBOOLEAN seen_mantissa = FALSE; /* memorize if mantissa has been
559 int stored_power = 0; /* power that matches the mantissa
561 TBOOLEAN got_hash = FALSE;
564 /*{{{ copy to dest until % */
565 while (*format != '%')
566 if (!(*dest++ = *format++))
567 return; /* end of format */
570 /*{{{ check for %% */
571 if (format[1] == '%') {
578 /*{{{ copy format part to temp, excluding conversion character */
581 if (format[1] == '#') {
586 /* dont put isdigit first since sideeffect in macro is bad */
587 while (*++format == '.' || isdigit((unsigned char) *format)
588 || *format == '-' || *format == '+' || *format == ' '
593 /*{{{ convert conversion character */
602 sprintf(dest, temp, (int) x);
614 sprintf(dest, temp, x);
617 /*{{{ l --- mantissa to current log base */
624 mant_exp(log10_base, x, FALSE, &mantissa, &stored_power, temp);
625 seen_mantissa = TRUE;
626 sprintf(dest, temp, mantissa);
630 /*{{{ t --- base-10 mantissa */
637 mant_exp(1.0, x, FALSE, &mantissa, &stored_power, temp);
638 seen_mantissa = TRUE;
639 sprintf(dest, temp, mantissa);
643 /*{{{ s --- base-1000 / 'scientific' mantissa */
650 mant_exp(1.0, x, TRUE, &mantissa, &stored_power, temp);
651 seen_mantissa = TRUE;
652 sprintf(dest, temp, mantissa);
656 /*{{{ L --- power to current log base */
664 power = stored_power;
666 mant_exp(log10_base, x, FALSE, NULL, &power, "%.0f");
667 sprintf(dest, temp, power);
671 /*{{{ T --- power of ten */
679 power = stored_power;
681 mant_exp(1.0, x, FALSE, NULL, &power, "%.0f");
682 sprintf(dest, temp, power);
686 /*{{{ S --- power of 1000 / 'scientific' */
694 power = stored_power;
696 mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
697 sprintf(dest, temp, power);
701 /*{{{ c --- ISO decimal unit prefix letters */
709 power = stored_power;
711 mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
713 if (power >= -18 && power <= 18) {
714 /* -18 -> 0, 0 -> 6, +18 -> 12, ... */
715 /* HBB 20010121: avoid division of -ve ints! */
716 power = (power + 18) / 3;
717 sprintf(dest, temp, "afpnum kMGTPE"[power]);
719 /* please extend the range ! */
720 /* name power name power
721 -------------------------
729 /* for the moment, print e+21 for example */
730 sprintf(dest, "e%+02d", (power - 6) * 3);
736 /*{{{ P --- multiple of pi */
741 sprintf(dest, temp, x / M_PI);
746 int_error(NO_CARET, "Bad format character");
750 if (got_hash && (format != strpbrk(format,"oeEfFgG")))
751 int_error(NO_CARET, "Bad format character");
753 /* change decimal `.' to the actual entry in decimalsign */
754 if (decimalsign != NULL) {
755 char *dotpos1 = dest, *dotpos2;
756 size_t newlength = strlen(decimalsign);
759 /* dot is the default decimalsign we will be replacing */
761 dot = *(localeconv()->decimal_point);
766 /* replace every dot by the contents of decimalsign */
767 while ((dotpos2 = strchr(dotpos1,dot)) != NULL) {
768 size_t taillength = strlen(dotpos2);
770 dotpos1 = dotpos2 + newlength;
771 /* test if the new value for dest would be too long */
772 if (dotpos1 - dest + taillength > count)
774 "format too long due to long decimalsign string");
775 /* move tail end of string out of the way */
776 memmove(dotpos1, dotpos2 + 1, taillength);
777 /* insert decimalsign */
778 memcpy(dotpos2, decimalsign, newlength);
780 /* clear temporary variables for safety */
785 /* this was at the end of every single case, before: */
786 dest += strlen(dest);
796 /* some macros for the error and warning functions below
797 * may turn this into a utility function later
799 #define PRINT_MESSAGE_TO_STDERR \
801 fprintf(stderr, "\n%s%s\n", \
802 current_prompt ? current_prompt : "", \
806 #define PRINT_SPACES_UNDER_PROMPT \
810 if (!current_prompt) \
812 for (p = current_prompt; *p != '\0'; p++) \
813 (void) fputc(' ', stderr); \
816 #define PRINT_SPACES_UPTO_TOKEN \
820 for (i = 0; i < token[t_num].start_index; i++) \
821 (void) fputc((gp_input_line[i] == '\t') ? '\t' : ' ', stderr); \
824 #define PRINT_CARET fputs("^\n",stderr);
826 #define PRINT_FILE_AND_LINE \
827 if (!interactive) { \
828 if (infile_name != NULL) \
829 fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num); \
830 else fprintf(stderr, "line %d: ", inline_num); \
833 /* TRUE if command just typed; becomes FALSE whenever we
834 * send some other output to screen. If FALSE, the command line
835 * will be echoed to the screen before the ^ error message.
839 #if defined(VA_START) && defined(STDC_HEADERS)
841 os_error(int t_num, const char *str,...)
844 os_error(int t_num, const char *str, va_dcl)
851 static status[2] = { 1, 0 }; /* 1 is count of error msgs */
854 /* reprint line if screen has been written to */
856 if (t_num == DATAFILE) {
858 } else if (t_num != NO_CARET) { /* put caret under error */
860 PRINT_MESSAGE_TO_STDERR;
862 PRINT_SPACES_UNDER_PROMPT;
863 PRINT_SPACES_UPTO_TOKEN;
866 PRINT_SPACES_UNDER_PROMPT;
870 # if defined(HAVE_VFPRINTF) || _LIBC
871 vfprintf(stderr, str, args);
873 _doprnt(str, args, stderr);
877 fprintf(stderr, str, a1, a2, a3, a4, a5, a6, a7, a8);
881 PRINT_SPACES_UNDER_PROMPT;
885 status[1] = vaxc$errno;
887 (void) putc('\n', stderr);
893 bail_to_command_line();
897 #if defined(VA_START) && defined(STDC_HEADERS)
899 int_error(int t_num, const char *str,...)
902 int_error(int t_num, const char str[], va_dcl)
909 /* reprint line if screen has been written to */
911 if (t_num == DATAFILE) {
913 } else if (t_num != NO_CARET) { /* put caret under error */
915 PRINT_MESSAGE_TO_STDERR;
917 PRINT_SPACES_UNDER_PROMPT;
918 PRINT_SPACES_UPTO_TOKEN;
921 PRINT_SPACES_UNDER_PROMPT;
926 # if defined(HAVE_VFPRINTF) || _LIBC
927 vfprintf(stderr, str, args);
929 _doprnt(str, args, stderr);
933 fprintf(stderr, str, a1, a2, a3, a4, a5, a6, a7, a8);
935 fputs("\n\n", stderr);
937 /* We are bailing out of nested context without ever reaching */
938 /* the normal cleanup code. Reset any flags before bailing. */
939 df_reset_after_error();
941 update_gpval_variables(2);
943 bail_to_command_line();
946 /* Warn without bailing out to command line. Not a user error */
947 #if defined(VA_START) && defined(STDC_HEADERS)
949 int_warn(int t_num, const char *str,...)
952 int_warn(int t_num, const char str[], va_dcl)
959 /* reprint line if screen has been written to */
961 if (t_num == DATAFILE) {
963 } else if (t_num != NO_CARET) { /* put caret under error */
965 PRINT_MESSAGE_TO_STDERR;
967 PRINT_SPACES_UNDER_PROMPT;
968 PRINT_SPACES_UPTO_TOKEN;
971 PRINT_SPACES_UNDER_PROMPT;
974 fputs("warning: ", stderr);
977 # if defined(HAVE_VFPRINTF) || _LIBC
978 vfprintf(stderr, str, args);
980 _doprnt(str, args, stderr);
984 fprintf(stderr, str, a1, a2, a3, a4, a5, a6, a7, a8);
985 #endif /* VA_START */
989 /*{{{ graph_error() */
990 /* handle errors during graph-plot in a consistent way */
991 /* HBB 20000430: move here, from graphics.c */
992 #if defined(VA_START) && defined(STDC_HEADERS)
994 graph_error(const char *fmt, ...)
997 graph_error(const char *fmt, va_dcl)
1008 VA_START(args, fmt);
1010 /* HBB 20001120: this seems not to work at all. Probably because a
1011 * va_list argument, is, after all, something else than a varargs
1012 * list (i.e. a '...') */
1013 int_error(NO_CARET, fmt, args);
1015 /* HBB 20001120: instead, copy the core code from int_error() to
1017 PRINT_SPACES_UNDER_PROMPT;
1018 PRINT_FILE_AND_LINE;
1020 # if defined(HAVE_VFPRINTF) || _LIBC
1021 vfprintf(stderr, fmt, args);
1023 _doprnt(fmt, args, stderr);
1026 fputs("\n\n", stderr);
1028 bail_to_command_line();
1032 int_error(NO_CARET, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
1040 /* Lower-case the given string (DFK) */
1041 /* Done in place. */
1048 if (isupper((unsigned char)*p))
1049 *p = tolower((unsigned char)*p);
1054 /* Squash spaces in the given string (DFK) */
1055 /* That is, reduce all multiple white-space chars to single spaces */
1056 /* Done in place. */
1058 squash_spaces(char *s)
1060 char *r = s; /* reading point */
1061 char *w = s; /* writing point */
1062 TBOOLEAN space = FALSE; /* TRUE if we've already copied a space */
1064 for (w = r = s; *r != NUL; r++) {
1065 if (isspace((unsigned char) *r)) {
1066 /* white space; only copy if we haven't just copied a space */
1070 } /* else ignore multiple spaces */
1072 /* non-space character; copy it and clear flag */
1077 *w = NUL; /* null terminate string */
1081 /* postprocess single quoted strings: replace "''" by "'"
1084 parse_sq(char *instr)
1086 char *s = instr, *t = instr;
1088 /* the string will always get shorter, so we can do the
1089 * conversion in situ
1093 if (*s == '\'' && *(s+1) == '\'')
1102 parse_esc(char *instr)
1104 char *s = instr, *t = instr;
1106 /* the string will always get shorter, so we can do the
1107 * conversion in situ
1116 } else if (*s == 'n') {
1119 } else if (*s == 'r') {
1122 } else if (*s == 't') {
1125 } else if (*s == '\"') {
1128 } else if (*s >= '0' && *s <= '7') {
1130 char *octal = (*s == '0' ? "%4o%n" : "%3o%n");
1131 if (sscanf(s, octal, &i, &n) > 0) {
1135 /* int_error("illegal octal number ", c_token); */
1140 } else if (df_separator && *s == '\"' && *(s+1) == '\"') {
1141 /* EAM Mar 2003 - For parsing CSV strings with quoted quotes */
1151 /* FIXME HH 20020915: This function does nothing if dirent.h and windows.h
1154 existdir (const char *name)
1156 #ifdef HAVE_DIRENT_H
1158 if (! (dp = opendir(name) ) )
1163 #elif defined(_Windows)
1165 WIN32_FIND_DATA finddata;
1167 FileHandle = FindFirstFile(name, &finddata);
1168 if (FileHandle != INVALID_HANDLE_VALUE) {
1169 if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1177 "Test on directory existence not supported\n\t('%s!')",
1186 char *username = NULL;
1187 char *fullname = NULL;
1189 username=getenv("USER");
1191 username=getenv("USERNAME");
1195 struct passwd *pwentry = NULL;
1196 pwentry=getpwnam(username);
1197 if (pwentry && strlen(pwentry->pw_gecos)) {
1198 fullname = gp_alloc(strlen(pwentry->pw_gecos)+1,"getusername");
1199 strcpy(fullname, pwentry->pw_gecos);
1201 fullname = gp_alloc(strlen(username)+1,"getusername");
1202 strcpy(fullname, username);
1205 #elif defined(_Windows)
1207 DWORD bufCharCount = INFO_BUFFER_SIZE;
1208 fullname = gp_alloc(INFO_BUFFER_SIZE + 1,"getusername");
1209 if (!GetUserName(fullname,&bufCharCount)) {
1215 fullname = gp_alloc(strlen(username)+1,"getusername");
1216 strcpy(fullname, username);
1217 #endif /* HAVE_PWD_H */