#ifndef lint static char *RCSid = "$Id: util.c,v 3.26 92/03/24 22:34:43 woo Exp Locker: woo $"; #endif /* GNUPLOT - util.c */ /* * Copyright (C) 1986, 1987, 1990, 1991, 1992 Thomas Williams, Colin Kelley * * Permission to use, copy, and distribute this software and its * documentation for any purpose with or without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. * * Permission to modify the software is granted, but not the right to * distribute the modified code. Modifications are to be distributed * as patches to released version. * * This software is provided "as is" without express or implied warranty. * * * AUTHORS * * Original Software: * Thomas Williams, Colin Kelley. * * Gnuplot 2.0 additions: * Russell Lang, Dave Kotz, John Campbell. * * Gnuplot 3.0 additions: * Gershon Elber and many others. * * Send your comments or suggestions to * info-gnuplot@ames.arc.nasa.gov. * This is a mailing list; to join it send a note to * info-gnuplot-request@ames.arc.nasa.gov. * Send bug reports to * bug-gnuplot@ames.arc.nasa.gov. */ #include #include #include #include #include "plot.h" BOOLEAN screen_ok; /* TRUE if command just typed; becomes FALSE whenever we send some other output to screen. If FALSE, the command line will be echoed to the screen before the ^ error message. */ #ifndef vms #ifndef __ZTC__ extern int errno; extern int sys_nerr; extern char *sys_errlist[]; #endif #endif /* vms */ extern char input_line[]; extern struct lexical_unit token[]; extern jmp_buf env; /* from plot.c */ extern int inline_num; /* from command.c */ extern BOOLEAN interactive; /* from plot.c */ extern char *infile_name; /* from plot.c */ extern char *strchr(); #ifndef AMIGA_AC_5 extern double sqrt(), atan2(); #endif /* * chr_in_str() compares the characters in the string of token number t_num * with c, and returns TRUE if a match was found. */ chr_in_str(t_num, c) int t_num; char c; { register int i; if (!token[t_num].is_token) return(FALSE); /* must be a value--can't be equal */ for (i = 0; i < token[t_num].length; i++) { if (input_line[token[t_num].start_index+i] == c) return(TRUE); } return FALSE; } /* * equals() compares string value of token number t_num with str[], and * returns TRUE if they are identical. */ equals(t_num, str) int t_num; char *str; { register int i; if (!token[t_num].is_token) return(FALSE); /* must be a value--can't be equal */ for (i = 0; i < token[t_num].length; i++) { if (input_line[token[t_num].start_index+i] != str[i]) return(FALSE); } /* now return TRUE if at end of str[], FALSE if not */ return(str[i] == '\0'); } /* * almost_equals() compares string value of token number t_num with str[], and * returns TRUE if they are identical up to the first $ in str[]. */ almost_equals(t_num, str) int t_num; char *str; { register int i; register int after = 0; register start = token[t_num].start_index; register length = token[t_num].length; if (!token[t_num].is_token) return(FALSE); /* must be a value--can't be equal */ for (i = 0; i < length + after; i++) { if (str[i] != input_line[start + i]) { if (str[i] != '$') return(FALSE); else { after = 1; start--; /* back up token ptr */ } } } /* i now beyond end of token string */ return(after || str[i] == '$' || str[i] == '\0'); } isstring(t_num) int t_num; { return(token[t_num].is_token && (input_line[token[t_num].start_index] == '\'' || input_line[token[t_num].start_index] == '\"')); } isnumber(t_num) int t_num; { return(!token[t_num].is_token); } isletter(t_num) int t_num; { return(token[t_num].is_token && ((isalpha(input_line[token[t_num].start_index]))|| (input_line[token[t_num].start_index] == '_'))); } /* * is_definition() returns TRUE if the next tokens are of the form * identifier = * -or- * identifier ( identifer ) = */ is_definition(t_num) int t_num; { return (isletter(t_num) && (equals(t_num+1,"=") || /* variable */ (equals(t_num+1,"(") && /* function */ isletter(t_num+2) && equals(t_num+3,")") && equals(t_num+4,"=") ) || (equals(t_num+1,"(") && /* function with */ isletter(t_num+2) && /* two variables */ equals(t_num+3,",") && isletter(t_num+4) && equals(t_num+5,")") && equals(t_num+6,"=") ) )); } /* * copy_str() copies the string in token number t_num into str, appending * a null. No more than MAX_ID_LEN chars are copied. */ copy_str(str, t_num) char str[]; int t_num; { register int i = 0; register int start = token[t_num].start_index; register int count; if ((count = token[t_num].length) > MAX_ID_LEN) count = MAX_ID_LEN; do { str[i++] = input_line[start++]; } while (i != count); str[i] = '\0'; } /* * quote_str() does the same thing as copy_str, except it ignores the * quotes at both ends. This seems redundant, but is done for * efficency. */ quote_str(str, t_num) char str[]; int t_num; { register int i = 0; register int start = token[t_num].start_index + 1; register int count; if ((count = token[t_num].length - 2) > MAX_ID_LEN) count = MAX_ID_LEN; if (count>0) { do { str[i++] = input_line[start++]; } while (i != count); } str[i] = '\0'; } /* * quotel_str() does the same thing as quote_str, except it uses * MAX_LINE_LEN instead of MAX_ID_LEN. */ quotel_str(str, t_num) char str[]; int t_num; { register int i = 0; register int start = token[t_num].start_index + 1; register int count; if ((count = token[t_num].length - 2) > MAX_LINE_LEN) count = MAX_LINE_LEN; if (count>0) { do { str[i++] = input_line[start++]; } while (i != count); } str[i] = '\0'; } /* * capture() copies into str[] the part of input_line[] which lies between * the begining of token[start] and end of token[end]. */ capture(str,start,end) char str[]; int start,end; { register int i,e; e = token[end].start_index + token[end].length; for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++) *str++ = input_line[i]; *str = '\0'; } /* * m_capture() is similar to capture(), but it mallocs storage for the * string. */ m_capture(str,start,end) char **str; int start,end; { register int i,e; register char *s; if (*str) /* previous pointer to malloc'd memory there */ free(*str); e = token[end].start_index + token[end].length; *str = alloc((unsigned int)(e - token[start].start_index + 1), "string"); s = *str; for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++) *s++ = input_line[i]; *s = '\0'; } /* * m_quote_capture() is similar to m_capture(), but it removes quotes from either end if the string. */ m_quote_capture(str,start,end) char **str; int start,end; { register int i,e; register char *s; if (*str) /* previous pointer to malloc'd memory there */ free(*str); e = token[end].start_index + token[end].length-1; *str = alloc((unsigned int)(e - token[start].start_index + 1), "string"); s = *str; for (i = token[start].start_index + 1; i < e && input_line[i] != '\0'; i++) *s++ = input_line[i]; *s = '\0'; } convert(val_ptr, t_num) struct value *val_ptr; int t_num; { *val_ptr = token[t_num].l_val; } static char *num_to_str(r) double r; { static i = 0; static char s[4][20]; int j = i++; if ( i > 3 ) i = 0; sprintf( s[j], "%g", r ); if ( strchr( s[j], '.' ) == NULL && strchr( s[j], 'e' ) == NULL && strchr( s[j], 'E' ) == NULL ) strcat( s[j], ".0" ); return s[j]; } disp_value(fp,val) FILE *fp; struct value *val; { switch(val->type) { case INT: fprintf(fp,"%d",val->v.int_val); break; case CMPLX: if (val->v.cmplx_val.imag != 0.0 ) fprintf(fp,"{%s, %s}", num_to_str(val->v.cmplx_val.real), num_to_str(val->v.cmplx_val.imag)); else fprintf(fp,"%s", num_to_str(val->v.cmplx_val.real)); break; default: int_error("unknown type in disp_value()",NO_CARET); } } double real(val) /* returns the real part of val */ struct value *val; { switch(val->type) { case INT: return((double) val->v.int_val); case CMPLX: return(val->v.cmplx_val.real); } int_error("unknown type in real()",NO_CARET); /* NOTREACHED */ return((double)0.0); } double imag(val) /* returns the imag part of val */ struct value *val; { switch(val->type) { case INT: return(0.0); case CMPLX: return(val->v.cmplx_val.imag); } int_error("unknown type in imag()",NO_CARET); /* NOTREACHED */ return((double)0.0); } double magnitude(val) /* returns the magnitude of val */ struct value *val; { switch(val->type) { case INT: return((double) abs(val->v.int_val)); case CMPLX: return(sqrt(val->v.cmplx_val.real* val->v.cmplx_val.real + val->v.cmplx_val.imag* val->v.cmplx_val.imag)); } int_error("unknown type in magnitude()",NO_CARET); /* NOTREACHED */ return((double)0.0); } double angle(val) /* returns the angle of val */ struct value *val; { switch(val->type) { case INT: return((val->v.int_val > 0) ? 0.0 : Pi); case CMPLX: if (val->v.cmplx_val.imag == 0.0) { if (val->v.cmplx_val.real >= 0.0) return(0.0); else return(Pi); } return(atan2(val->v.cmplx_val.imag, val->v.cmplx_val.real)); } int_error("unknown type in angle()",NO_CARET); /* NOTREACHED */ return((double)0.0); } struct value * complex(a,realpart,imagpart) struct value *a; double realpart, imagpart; { a->type = CMPLX; a->v.cmplx_val.real = realpart; a->v.cmplx_val.imag = imagpart; return(a); } struct value * integer(a,i) struct value *a; int i; { a->type = INT; a->v.int_val = i; return(a); } os_error(str,t_num) char str[]; int t_num; { #ifdef vms static status[2] = {1, 0}; /* 1 is count of error msgs */ #endif register int i; /* reprint line if screen has been written to */ if (t_num != NO_CARET) { /* put caret under error */ if (!screen_ok) fprintf(stderr,"\n%s%s\n", PROMPT, input_line); for (i = 0; i < sizeof(PROMPT) - 1; i++) (void) putc(' ',stderr); for (i = 0; i < token[t_num].start_index; i++) { (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr); } (void) putc('^',stderr); (void) putc('\n',stderr); } for (i = 0; i < sizeof(PROMPT) - 1; i++) (void) putc(' ',stderr); fprintf(stderr,"%s\n",str); for (i = 0; i < sizeof(PROMPT) - 1; i++) (void) putc(' ',stderr); if (!interactive) if (infile_name != NULL) fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num); else fprintf(stderr,"line %d: ", inline_num); #ifdef vms status[1] = vaxc$errno; sys$putmsg(status); (void) putc('\n',stderr); #else #ifdef __ZTC__ fprintf(stderr,"error number %d\n\n",errno); #else if (errno >= sys_nerr) fprintf(stderr, "unknown errno %d\n\n", errno); else fprintf(stderr,"(%s)\n\n",sys_errlist[errno]); #endif #endif longjmp(env, TRUE); /* bail out to command line */ } int_error(str,t_num) char str[]; int t_num; { register int i; /* reprint line if screen has been written to */ if (t_num != NO_CARET) { /* put caret under error */ if (!screen_ok) fprintf(stderr,"\n%s%s\n", PROMPT, input_line); for (i = 0; i < sizeof(PROMPT) - 1; i++) (void) putc(' ',stderr); for (i = 0; i < token[t_num].start_index; i++) { (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr); } (void) putc('^',stderr); (void) putc('\n',stderr); } for (i = 0; i < sizeof(PROMPT) - 1; i++) (void) putc(' ',stderr); if (!interactive) if (infile_name != NULL) fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num); else fprintf(stderr,"line %d: ", inline_num); fprintf(stderr,"%s\n\n", str); longjmp(env, TRUE); /* bail out to command line */ } /* Lower-case the given string (DFK) */ /* Done in place. */ void lower_case(s) char *s; { register char *p = s; while (*p != '\0') { if (isupper(*p)) *p = tolower(*p); p++; } } /* Squash spaces in the given string (DFK) */ /* That is, reduce all multiple white-space chars to single spaces */ /* Done in place. */ void squash_spaces(s) char *s; { register char *r = s; /* reading point */ register char *w = s; /* writing point */ BOOLEAN space = FALSE; /* TRUE if we've already copied a space */ for (w = r = s; *r != '\0'; r++) { if (isspace(*r)) { /* white space; only copy if we haven't just copied a space */ if (!space) { space = TRUE; *w++ = ' '; } /* else ignore multiple spaces */ } else { /* non-space character; copy it and clear flag */ *w++ = *r; space = FALSE; } } *w = '\0'; /* null terminate string */ }