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