Annotation of OpenXM_contrib/gnuplot/util.c, Revision 1.1.1.1
1.1 maekawa 1: #ifndef lint
2: static char *RCSid = "$Id: util.c,v 1.46 1998/06/18 14:55:20 ddenholm Exp $";
3: #endif
4:
5: /* GNUPLOT - util.c */
6:
7: /*[
8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
9: *
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.
15: *
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,
20: * provided you
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
28: * software.
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.
32: *
33: * This software is provided "as is" without express or implied warranty
34: * to the extent permitted by applicable law.
35: ]*/
36:
37:
38: #include "plot.h"
39: #include "setshow.h" /* for month names etc */
40:
41:
42: /* TRUE if command just typed; becomes FALSE whenever we
43: * send some other output to screen. If FALSE, the command line
44: * will be echoed to the screen before the ^ error message.
45: */
46: TBOOLEAN screen_ok;
47:
48: static char *num_to_str __PROTO((double r));
49: static void parse_esc __PROTO((char *instr));
50:
51: /*
52: * chr_in_str() compares the characters in the string of token number t_num
53: * with c, and returns TRUE if a match was found.
54: */
55: int chr_in_str(t_num, c)
56: int t_num;
57: int c;
58: {
59: register int i;
60:
61: if (!token[t_num].is_token)
62: return (FALSE); /* must be a value--can't be equal */
63: for (i = 0; i < token[t_num].length; i++) {
64: if (input_line[token[t_num].start_index + i] == c)
65: return (TRUE);
66: }
67: return FALSE;
68: }
69:
70:
71: /*
72: * equals() compares string value of token number t_num with str[], and
73: * returns TRUE if they are identical.
74: */
75: int equals(t_num, str)
76: int t_num;
77: char *str;
78: {
79: register int i;
80:
81: if (!token[t_num].is_token)
82: return (FALSE); /* must be a value--can't be equal */
83: for (i = 0; i < token[t_num].length; i++) {
84: if (input_line[token[t_num].start_index + i] != str[i])
85: return (FALSE);
86: }
87: /* now return TRUE if at end of str[], FALSE if not */
88: return (str[i] == NUL);
89: }
90:
91:
92:
93: /*
94: * almost_equals() compares string value of token number t_num with str[], and
95: * returns TRUE if they are identical up to the first $ in str[].
96: */
97: int almost_equals(t_num, str)
98: int t_num;
99: char *str;
100: {
101: register int i;
102: register int after = 0;
103: register int start = token[t_num].start_index;
104: register int length = token[t_num].length;
105:
106: if (!token[t_num].is_token)
107: return (FALSE); /* must be a value--can't be equal */
108: for (i = 0; i < length + after; i++) {
109: if (str[i] != input_line[start + i]) {
110: if (str[i] != '$')
111: return (FALSE);
112: else {
113: after = 1;
114: start--; /* back up token ptr */
115: }
116: }
117: }
118:
119: /* i now beyond end of token string */
120:
121: return (after || str[i] == '$' || str[i] == NUL);
122: }
123:
124:
125:
126: int isstring(t_num)
127: int t_num;
128: {
129:
130: return (token[t_num].is_token &&
131: (input_line[token[t_num].start_index] == '\'' ||
132: input_line[token[t_num].start_index] == '"'));
133: }
134:
135:
136: int isanumber(t_num)
137: int t_num;
138: {
139: return (!token[t_num].is_token);
140: }
141:
142:
143: int isletter(t_num)
144: int t_num;
145: {
146: return (token[t_num].is_token &&
147: ((isalpha((int)input_line[token[t_num].start_index])) ||
148: (input_line[token[t_num].start_index] == '_')));
149: }
150:
151:
152: /*
153: * is_definition() returns TRUE if the next tokens are of the form
154: * identifier =
155: * -or-
156: * identifier ( identifer {,identifier} ) =
157: */
158: int is_definition(t_num)
159: int t_num;
160: {
161: /* variable? */
162: if (isletter(t_num) && equals(t_num + 1, "="))
163: return 1;
164:
165: /* function? */
166: /* look for dummy variables */
167: if (isletter(t_num) && equals(t_num + 1, "(") && isletter(t_num + 2)) {
168: t_num += 3; /* point past first dummy */
169: while (equals(t_num, ",")) {
170: if (!isletter(++t_num))
171: return 0;
172: t_num += 1;
173: }
174: return (equals(t_num, ")") && equals(t_num + 1, "="));
175: }
176: /* neither */
177: return 0;
178: }
179:
180:
181:
182: /*
183: * copy_str() copies the string in token number t_num into str, appending
184: * a null. No more than max chars are copied (including \0).
185: */
186: void copy_str(str, t_num, max)
187: char str[];
188: int t_num;
189: int max;
190: {
191: register int i = 0;
192: register int start = token[t_num].start_index;
193: register int count;
194:
195: if ((count = token[t_num].length) >= max) {
196: count = max - 1;
197: FPRINTF((stderr, "str buffer overflow in copy_str"));
198: }
199: do {
200: str[i++] = input_line[start++];
201: } while (i != count);
202: str[i] = NUL;
203: }
204:
205: /* length of token string */
206: int token_len(t_num)
207: int t_num;
208: {
209: return (token[t_num].length);
210: }
211:
212: /*
213: * quote_str() does the same thing as copy_str, except it ignores the
214: * quotes at both ends. This seems redundant, but is done for
215: * efficency.
216: */
217: void quote_str(str, t_num, max)
218: char str[];
219: int t_num;
220: int max;
221: {
222: register int i = 0;
223: register int start = token[t_num].start_index + 1;
224: register int count;
225:
226: if ((count = token[t_num].length - 2) >= max) {
227: count = max - 1;
228: FPRINTF((stderr, "str buffer overflow in quote_str"));
229: }
230: if (count > 0) {
231: do {
232: str[i++] = input_line[start++];
233: } while (i != count);
234: }
235: str[i] = NUL;
236: /* convert \t and \nnn (octal) to char if in double quotes */
237: if (input_line[token[t_num].start_index] == '"')
238: parse_esc(str);
239: }
240:
241:
242: /*
243: * capture() copies into str[] the part of input_line[] which lies between
244: * the begining of token[start] and end of token[end].
245: */
246: void capture(str, start, end, max)
247: char str[];
248: int start, end;
249: int max;
250: {
251: register int i, e;
252:
253: e = token[end].start_index + token[end].length;
254: if (e - token[start].start_index >= max) {
255: e = token[start].start_index + max - 1;
256: FPRINTF((stderr, "str buffer overflow in capture"));
257: }
258: for (i = token[start].start_index; i < e && input_line[i] != NUL; i++)
259: *str++ = input_line[i];
260: *str = NUL;
261: }
262:
263:
264: /*
265: * m_capture() is similar to capture(), but it mallocs storage for the
266: * string.
267: */
268: void m_capture(str, start, end)
269: char **str;
270: int start, end;
271: {
272: register int i, e;
273: register char *s;
274:
275: if (*str) /* previous pointer to malloc'd memory there */
276: free(*str);
277: e = token[end].start_index + token[end].length;
278: *str = gp_alloc((unsigned long) (e - token[start].start_index + 1), "string");
279: s = *str;
280: for (i = token[start].start_index; i < e && input_line[i] != NUL; i++)
281: *s++ = input_line[i];
282: *s = NUL;
283: }
284:
285:
286: /*
287: * m_quote_capture() is similar to m_capture(), but it removes
288: quotes from either end if the string.
289: */
290: void m_quote_capture(str, start, end)
291: char **str;
292: int start, end;
293: {
294: register int i, e, escflag = 0;
295: register char *s;
296:
297: if (*str) /* previous pointer to malloc'd memory there */
298: free(*str);
299: e = token[end].start_index + token[end].length - 1;
300: *str = gp_alloc((unsigned long) (e - token[start].start_index + 1), "string");
301: s = *str;
302: for (i = token[start].start_index + 1; i < e && input_line[i] != NUL; i++)
303: if ((*s++ = input_line[i]) == '\\') ++escflag;
304: *s = NUL;
305: if (escflag) parse_esc(*str);
306: }
307:
308:
309: void convert(val_ptr, t_num)
310: struct value *val_ptr;
311: int t_num;
312: {
313: *val_ptr = token[t_num].l_val;
314: }
315:
316: static char *num_to_str(r)
317: double r;
318: {
319: static int i = 0;
320: static char s[4][25];
321: int j = i++;
322:
323: if (i > 3)
324: i = 0;
325:
326: sprintf(s[j], "%.15g", r);
327: if (strchr(s[j], '.') == NULL &&
328: strchr(s[j], 'e') == NULL &&
329: strchr(s[j], 'E') == NULL)
330: strcat(s[j], ".0");
331:
332: return s[j];
333: }
334:
335: void disp_value(fp, val)
336: FILE *fp;
337: struct value *val;
338: {
339: switch (val->type) {
340: case INTGR:
341: fprintf(fp, "%d", val->v.int_val);
342: break;
343: case CMPLX:
344: if (val->v.cmplx_val.imag != 0.0)
345: fprintf(fp, "{%s, %s}",
346: num_to_str(val->v.cmplx_val.real),
347: num_to_str(val->v.cmplx_val.imag));
348: else
349: fprintf(fp, "%s",
350: num_to_str(val->v.cmplx_val.real));
351: break;
352: default:
353: int_error("unknown type in disp_value()", NO_CARET);
354: }
355: }
356:
357:
358: double real(val) /* returns the real part of val */
359: struct value *val;
360: {
361: switch (val->type) {
362: case INTGR:
363: return ((double) val->v.int_val);
364: case CMPLX:
365: return (val->v.cmplx_val.real);
366: }
367: int_error("unknown type in real()", NO_CARET);
368: /* NOTREACHED */
369: return ((double) 0.0);
370: }
371:
372:
373: double imag(val) /* returns the imag part of val */
374: struct value *val;
375: {
376: switch (val->type) {
377: case INTGR:
378: return (0.0);
379: case CMPLX:
380: return (val->v.cmplx_val.imag);
381: }
382: int_error("unknown type in imag()", NO_CARET);
383: /* NOTREACHED */
384: return ((double) 0.0);
385: }
386:
387:
388:
389: double magnitude(val) /* returns the magnitude of val */
390: struct value *val;
391: {
392: switch (val->type) {
393: case INTGR:
394: return ((double) abs(val->v.int_val));
395: case CMPLX:
396: return (sqrt(val->v.cmplx_val.real *
397: val->v.cmplx_val.real +
398: val->v.cmplx_val.imag *
399: val->v.cmplx_val.imag));
400: }
401: int_error("unknown type in magnitude()", NO_CARET);
402: /* NOTREACHED */
403: return ((double) 0.0);
404: }
405:
406:
407:
408: double angle(val) /* returns the angle of val */
409: struct value *val;
410: {
411: switch (val->type) {
412: case INTGR:
413: return ((val->v.int_val >= 0) ? 0.0 : Pi);
414: case CMPLX:
415: if (val->v.cmplx_val.imag == 0.0) {
416: if (val->v.cmplx_val.real >= 0.0)
417: return (0.0);
418: else
419: return (Pi);
420: }
421: return (atan2(val->v.cmplx_val.imag,
422: val->v.cmplx_val.real));
423: }
424: int_error("unknown type in angle()", NO_CARET);
425: /* NOTREACHED */
426: return ((double) 0.0);
427: }
428:
429:
430: struct value *
431: Gcomplex(a, realpart, imagpart)
432: struct value *a;
433: double realpart, imagpart;
434: {
435: a->type = CMPLX;
436: a->v.cmplx_val.real = realpart;
437: a->v.cmplx_val.imag = imagpart;
438: return (a);
439: }
440:
441:
442: struct value *
443: Ginteger(a, i)
444: struct value *a;
445: int i;
446: {
447: a->type = INTGR;
448: a->v.int_val = i;
449: return (a);
450: }
451:
452:
453: void os_error(str, t_num)
454: char str[];
455: int t_num;
456: {
457: #ifdef VMS
458: static status[2] =
459: {1, 0}; /* 1 is count of error msgs */
460: #endif /* VMS */
461:
462: register int i;
463:
464: /* reprint line if screen has been written to */
465:
466: if (t_num != NO_CARET) { /* put caret under error */
467: if (!screen_ok)
468: fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
469:
470: for (i = 0; i < sizeof(PROMPT) - 1; i++)
471: (void) putc(' ', stderr);
472: for (i = 0; i < token[t_num].start_index; i++) {
473: (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
474: }
475: (void) putc('^', stderr);
476: (void) putc('\n', stderr);
477: }
478: for (i = 0; i < sizeof(PROMPT) - 1; i++)
479: (void) putc(' ', stderr);
480: fputs(str, stderr);
481: putc('\n', stderr);
482:
483: for (i = 0; i < sizeof(PROMPT) - 1; i++)
484: (void) putc(' ', stderr);
485: if (!interactive) {
486: if (infile_name != NULL)
487: fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
488: else
489: fprintf(stderr, "line %d: ", inline_num);
490: }
491:
492:
493: #ifdef VMS
494: status[1] = vaxc$errno;
495: sys$putmsg(status);
496: (void) putc('\n', stderr);
497: #else /* VMS */
498: fprintf(stderr, "(%s)\n\n", strerror(errno));
499: #endif /* VMS */
500:
501: bail_to_command_line();
502: }
503:
504:
505: void int_error(str, t_num)
506: char str[];
507: int t_num;
508: {
509: register int i;
510:
511: /* reprint line if screen has been written to */
512:
513: if (t_num != NO_CARET) { /* put caret under error */
514: if (!screen_ok)
515: fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
516:
517: for (i = 0; i < sizeof(PROMPT) - 1; i++)
518: (void) putc(' ', stderr);
519: for (i = 0; i < token[t_num].start_index; i++) {
520: (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
521: }
522: (void) putc('^', stderr);
523: (void) putc('\n', stderr);
524: }
525: for (i = 0; i < sizeof(PROMPT) - 1; i++)
526: (void) putc(' ', stderr);
527: if (!interactive) {
528: if (infile_name != NULL)
529: fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
530: else
531: fprintf(stderr, "line %d: ", inline_num);
532: }
533: fputs(str, stderr);
534: fputs("\n\n", stderr);
535:
536: bail_to_command_line();
537: }
538:
539: /* Warn without bailing out to command line. Not a user error */
540: void int_warn(str, t_num)
541: char str[];
542: int t_num;
543: {
544: register int i;
545:
546: /* reprint line if screen has been written to */
547:
548: if (t_num != NO_CARET) { /* put caret under error */
549: if (!screen_ok)
550: fprintf(stderr, "\n%s%s\n", PROMPT, input_line);
551:
552: for (i = 0; i < sizeof(PROMPT) - 1; i++)
553: (void) putc(' ', stderr);
554: for (i = 0; i < token[t_num].start_index; i++) {
555: (void) putc((input_line[i] == '\t') ? '\t' : ' ', stderr);
556: }
557: (void) putc('^', stderr);
558: (void) putc('\n', stderr);
559: }
560: for (i = 0; i < sizeof(PROMPT) - 1; i++)
561: (void) putc(' ', stderr);
562: if (!interactive) {
563: if (infile_name != NULL)
564: fprintf(stderr, "\"%s\", line %d: ", infile_name, inline_num);
565: else
566: fprintf(stderr, "line %d: ", inline_num);
567: }
568: fprintf(stderr, "warning: %s\n", str);
569:
570: } /* int_warn */
571:
572: /* Lower-case the given string (DFK) */
573: /* Done in place. */
574: void lower_case(s)
575: char *s;
576: {
577: register char *p = s;
578:
579: while (*p != NUL) {
580: if (isupper((int)*p))
581: *p = tolower(*p);
582: p++;
583: }
584: }
585:
586: /* Squash spaces in the given string (DFK) */
587: /* That is, reduce all multiple white-space chars to single spaces */
588: /* Done in place. */
589: void squash_spaces(s)
590: char *s;
591: {
592: register char *r = s; /* reading point */
593: register char *w = s; /* writing point */
594: TBOOLEAN space = FALSE; /* TRUE if we've already copied a space */
595:
596: for (w = r = s; *r != NUL; r++) {
597: if (isspace((int)*r)) {
598: /* white space; only copy if we haven't just copied a space */
599: if (!space) {
600: space = TRUE;
601: *w++ = ' ';
602: } /* else ignore multiple spaces */
603: } else {
604: /* non-space character; copy it and clear flag */
605: *w++ = *r;
606: space = FALSE;
607: }
608: }
609: *w = NUL; /* null terminate string */
610: }
611:
612:
613: static void parse_esc(instr)
614: char *instr;
615: {
616: char *s = instr, *t = instr;
617:
618: /* the string will always get shorter, so we can do the
619: * conversion in situ
620: */
621:
622: while (*s != NUL) {
623: if (*s == '\\') {
624: s++;
625: if (*s == '\\') {
626: *t++ = '\\';
627: s++;
628: } else if (*s == 'n') {
629: *t++ = '\n';
630: s++;
631: } else if (*s == 'r') {
632: *t++ = '\r';
633: s++;
634: } else if (*s == 't') {
635: *t++ = '\t';
636: s++;
637: } else if (*s == '\"') {
638: *t++ = '\"';
639: s++;
640: } else if (*s >= '0' && *s <= '7') {
641: int i, n;
642: if (sscanf(s, "%o%n", &i, &n) > 0) {
643: *t++ = i;
644: s += n;
645: } else {
646: /* int_error("illegal octal number ", c_token); */
647: *t++ = '\\';
648: *t++ = *s++;
649: }
650: }
651: } else {
652: *t++ = *s++;
653: }
654: }
655: *t = NUL;
656: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>