Annotation of OpenXM_contrib/gnuplot/scanner.c, Revision 1.1.1.3
1.1 maekawa 1: #ifndef lint
1.1.1.3 ! ohara 2: static char *RCSid = "$Id: scanner.c,v 1.10.2.3 2002/03/11 16:10:09 lhecking Exp $";
1.1 maekawa 3: #endif
4:
5: /* GNUPLOT - scanner.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: #include "plot.h"
38:
39: static int get_num __PROTO((char str[]));
1.1.1.3 ! ohara 40: static void substitute __PROTO((char **, int *, int));
1.1 maekawa 41:
42: #ifdef AMIGA_AC_5
43: #define O_RDONLY 0
44: int open(const char *_name, int _mode,...);
45: int close(int);
46: #endif /* AMIGA_AC_5 */
47:
48: #ifdef VMS
49: #include <descrip.h>
50: #define MAILBOX "PLOT$MAILBOX"
51: #define pclose(f) fclose(f)
52: #ifdef __DECC
53: #include <lib$routines.h> /* avoid some IMPLICITFNC warnings */
54: #include <starlet.h>
55: #endif /* __DECC */
56: #endif /* VMS */
57:
58:
59: #define isident(c) (isalnum(c) || (c) == '_')
60:
61: #ifndef STDOUT
62: #define STDOUT 1
63: #endif
64:
65: #define LBRACE '{'
66: #define RBRACE '}'
67:
68: #define APPEND_TOKEN {token[t_num].length++; current++;}
69:
70: #define SCAN_IDENTIFIER while (isident((int)expression[current + 1]))\
71: APPEND_TOKEN
72:
73: static int t_num; /* number of token I'm working on */
74:
75: /*
76: * scanner() breaks expression[] into lexical units, storing them in token[].
1.1.1.3 ! ohara 77: * The total number of tokens found is returned as the function
! 78: * value. Scanning will stop when '\0' is found in expression[], or
! 79: * when token[] is full. extend_input_line() is called to extend
! 80: * expression array if needed.
1.1 maekawa 81: *
82: * Scanning is performed by following rules:
83: *
84: * Current char token should contain
85: * ------------- -----------------------
86: * 1. alpha,_ all following alpha-numerics
87: * 2. digit 0 or more following digits, 0 or 1 decimal point,
88: * 0 or more digits, 0 or 1 'e' or 'E',
89: * 0 or more digits.
90: * 3. ^,+,-,/ only current char
91: * %,~,(,)
92: * [,],;,:,
93: * ?,comma
94: * $ for using patch (div)
95: * 4. &,|,=,* current char; also next if next is same
96: * 5. !,<,> current char; also next if next is =
97: * 6. ", ' all chars up until matching quote
98: * 7. # this token cuts off scanning of the line (DFK).
1.1.1.3 ! ohara 99: * 8. ` (command substitution: all characters through the
! 100: * matching backtic are replaced by the output of
! 101: * the contained command, then scanning is restarted.)
1.1 maekawa 102: *
103: * white space between tokens is ignored
104: */
1.1.1.3 ! ohara 105: int
! 106: scanner(expressionp, expressionlenp)
! 107: char **expressionp;
! 108: int *expressionlenp;
1.1 maekawa 109: {
110: register int current; /* index of current char in expression[] */
1.1.1.3 ! ohara 111: char *expression = *expressionp;
1.1 maekawa 112: register int quote;
113: char brace;
114:
115: for (current = t_num = 0; expression[current] != NUL; current++) {
116: again:
117: if (t_num + 1 >= token_table_size) {
118: /* leave space for dummy end token */
119: extend_token_table();
120: }
121: if (isspace((int) expression[current]))
122: continue; /* skip the whitespace */
123: token[t_num].start_index = current;
124: token[t_num].length = 1;
125: token[t_num].is_token = TRUE; /* to start with... */
126:
127: if (expression[current] == '`') {
1.1.1.3 ! ohara 128: substitute(expressionp, expressionlenp, current);
! 129: expression = *expressionp; /* expression might have moved */
1.1 maekawa 130: goto again;
131: }
132: /* allow _ to be the first character of an identifier */
133: if (isalpha((int) expression[current]) || expression[current] == '_') {
134: SCAN_IDENTIFIER;
135: } else if (isdigit((int) expression[current]) || expression[current] == '.') {
136: token[t_num].is_token = FALSE;
137: token[t_num].length = get_num(&expression[current]);
138: current += (token[t_num].length - 1);
139: } else if (expression[current] == LBRACE) {
140: token[t_num].is_token = FALSE;
141: token[t_num].l_val.type = CMPLX;
142: #ifdef __PUREC__
143: {
144: char l[80];
145: if ((sscanf(&expression[++current], "%lf,%lf%[ }]s",
146: &token[t_num].l_val.v.cmplx_val.real,
147: &token[t_num].l_val.v.cmplx_val.imag,
148: &l) != 3) || (!strchr(l, RBRACE)))
149: int_error("invalid complex constant", t_num);
150: }
151: #else
152: if ((sscanf(&expression[++current], "%lf , %lf %c",
153: &token[t_num].l_val.v.cmplx_val.real,
154: &token[t_num].l_val.v.cmplx_val.imag,
155: &brace) != 3) || (brace != RBRACE))
156: int_error("invalid complex constant", t_num);
157: #endif
158: token[t_num].length += 2;
159: while (expression[++current] != RBRACE) {
160: token[t_num].length++;
161: if (expression[current] == NUL) /* { for vi % */
162: int_error("no matching '}'", t_num);
163: }
164: } else if (expression[current] == '\'' || expression[current] == '\"') {
165: token[t_num].length++;
166: quote = expression[current];
167: while (expression[++current] != quote) {
168: if (!expression[current]) {
169: expression[current] = quote;
170: expression[current + 1] = NUL;
171: break;
172: } else if (expression[current] == '\\'
173: && expression[current + 1]) {
174: current++;
175: token[t_num].length += 2;
1.1.1.3 ! ohara 176: } else if (quote == '\"' && expression[current] == '`') {
! 177: substitute(expressionp, expressionlenp, current);
! 178: expression = *expressionp; /* it might have moved */
! 179: current--;
1.1 maekawa 180: } else
181: token[t_num].length++;
182: }
183: } else
184: switch (expression[current]) {
185: case '#': /* DFK: add comments to gnuplot */
186: goto endline; /* ignore the rest of the line */
187: case '^':
188: case '+':
189: case '-':
190: case '/':
191: case '%':
192: case '~':
193: case '(':
194: case ')':
195: case '[':
196: case ']':
197: case ';':
198: case ':':
199: case '?':
200: case ',':
201: case '$': /* div */
202: break;
203: case '&':
204: case '|':
205: case '=':
206: case '*':
207: if (expression[current] == expression[current + 1])
208: APPEND_TOKEN;
209: break;
210: case '!':
211: case '<':
212: case '>':
213: if (expression[current + 1] == '=')
214: APPEND_TOKEN;
215: break;
216: default:
217: int_error("invalid character", t_num);
218: }
219: ++t_num; /* next token if not white space */
220: }
221:
222: endline: /* comments jump here to ignore line */
223:
224: /* Now kludge an extra token which points to '\0' at end of expression[].
225: This is useful so printerror() looks nice even if we've fallen off the
226: line. */
227:
228: token[t_num].start_index = current;
229: token[t_num].length = 0;
230: /* print 3+4 then print 3+ is accepted without
231: * this, since string is ignored if it is not
232: * a token
233: */
234: token[t_num].is_token = TRUE;
235: return (t_num);
236: }
237:
238:
239: static int get_num(str)
240: char str[];
241: {
242: register int count = 0;
243: register long lval;
244:
245: token[t_num].is_token = FALSE;
246: token[t_num].l_val.type = INTGR; /* assume unless . or E found */
247: while (isdigit((int) str[count]))
248: count++;
249: if (str[count] == '.') {
250: token[t_num].l_val.type = CMPLX;
251: /* swallow up digits until non-digit */
252: while (isdigit((int) str[++count]))
253: ;
254: /* now str[count] is other than a digit */
255: }
256: if (str[count] == 'e' || str[count] == 'E') {
257: token[t_num].l_val.type = CMPLX;
258: /* modified if statement to allow + sign in exponent
259: rjl 26 July 1988 */
260: count++;
261: if (str[count] == '-' || str[count] == '+')
262: count++;
263: if (!isdigit((int) str[count])) {
264: token[t_num].start_index += count;
265: int_error("expecting exponent", t_num);
266: }
267: while (isdigit((int) str[++count]));
268: }
269: if (token[t_num].l_val.type == INTGR) {
270: lval = atol(str);
271: if ((token[t_num].l_val.v.int_val = lval) != lval)
272: int_error("integer overflow; change to floating point", t_num);
273: } else {
274: token[t_num].l_val.v.cmplx_val.imag = 0.0;
275: token[t_num].l_val.v.cmplx_val.real = atof(str);
276: }
277: return (count);
278: }
279:
280: #if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
281:
282: /* A macro to reduce clutter ... */
283: # ifdef AMIGA_AC_5
284: # define CLOSE_FILE_OR_PIPE ((void) close(fd))
285: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
286: # define CLOSE_FILE_OR_PIPE ((void) fclose(f); (void) unlink(atari_tmpfile))
287: # else /* Rest of the world */
288: # define CLOSE_FILE_OR_PIPE ((void) pclose(f))
289: # endif
290:
1.1.1.3 ! ohara 291: /* substitute output from ` `
! 292: * *strp points to the input string. (*strp)[current] is expected to
! 293: * be the initial back tic. Characters through the following back tic
! 294: * are replaced by the output of the command. extend_input_line()
! 295: * is called to extend *strp array if needed.
! 296: */
! 297: static void substitute(strp, str_lenp, current)
! 298: char **strp;
! 299: int *str_lenp;
! 300: int current;
1.1 maekawa 301: {
302: register char *last;
1.1.1.3 ! ohara 303: register int c;
1.1 maekawa 304: register FILE *f;
305: # ifdef AMIGA_AC_5
306: int fd;
307: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
308: char *atari_tmpfile;
309: # endif /* !AMIGA_AC_5 */
1.1.1.3 ! ohara 310: char *str, *pgm, *rest = NULL;
! 311: int pgm_len, rest_len;
1.1 maekawa 312:
313: # ifdef VMS
314: int chan, one = 1;
1.1.1.3 ! ohara 315: struct dsc$descriptor_s pgmdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1.1 maekawa 316: static $DESCRIPTOR(lognamedsc, MAILBOX);
317: # endif /* VMS */
318:
319: /* forgive missing closing backquote at end of line */
1.1.1.3 ! ohara 320: str = *strp + current;
1.1 maekawa 321: last = str;
322: while (*++last) {
1.1.1.3 ! ohara 323: if (*last == '`')
1.1 maekawa 324: break;
1.1.1.3 ! ohara 325: }
! 326: pgm_len = last - str;
! 327: pgm = gp_alloc(pgm_len, "command string");
! 328: safe_strncpy(pgm, str + 1, pgm_len); /* omit ` to leave room for NUL */
! 329:
! 330: /* save rest of line, if any */
! 331: if (*last) {
! 332: last++; /* advance past ` */
! 333: rest_len = strlen(last) + 1;
! 334: if (rest_len > 1) {
! 335: rest = gp_alloc(rest_len, "input line copy");
! 336: strcpy(rest, last);
1.1 maekawa 337: }
338: }
339:
340: # ifdef VMS
1.1.1.3 ! ohara 341: pgmdsc.dsc$a_pointer = pgm;
! 342: pgmdsc.dsc$w_length = pgm_len;
1.1 maekawa 343: if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
344: os_error("sys$crembx failed", NO_CARET);
345:
346: if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
347: os_error("lib$spawn failed", NO_CARET);
348:
349: if ((f = fopen(MAILBOX, "r")) == NULL)
350: os_error("mailbox open failed", NO_CARET);
351: # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
352: if (system(NULL) == 0)
353: os_error("no command shell", NO_CARET);
354: atari_tmpfile = tmpnam(NULL);
1.1.1.3 ! ohara 355: gp_realloc(pgm, pgm_len + 5 + strlen(atari_tmpfile), "command string");
! 356: strcat(pgm, " >> ");
! 357: strcat(pgm, atari_tmpfile);
! 358: system(pgm);
1.1 maekawa 359: if ((f = fopen(atari_tmpfile, "r")) == NULL)
360: # elif defined(AMIGA_AC_5)
361: if ((fd = open(pgm, "O_RDONLY")) == -1)
362: # else /* everyone else */
363: if ((f = popen(pgm, "r")) == NULL)
364: os_error("popen failed", NO_CARET);
365: # endif /* !VMS */
366:
1.1.1.3 ! ohara 367: free(pgm);
! 368:
! 369: /* now replace ` ` with output */
! 370: while (1) {
! 371: # if defined(AMIGA_AC_5)
! 372: char ch;
! 373: if (read(fd, &ch, 1) != 1)
! 374: break;
! 375: c = ch;
! 376: # else
! 377: if ((c = getc(f)) == EOF)
! 378: break;
! 379: # endif /* !AMIGA_AC_5 */
! 380: /* newlines become blanks */
! 381: (*strp)[current++] = ((c == '\n') ? ' ' : c);
! 382: if (current == *str_lenp)
! 383: extend_input_line();
1.1 maekawa 384: }
1.1.1.3 ! ohara 385: (*strp)[current] = 0;
1.1 maekawa 386:
387: CLOSE_FILE_OR_PIPE;
388:
389: /* tack on rest of line to output */
1.1.1.3 ! ohara 390: if (rest) {
! 391: while (current + rest_len > *str_lenp)
! 392: extend_input_line();
! 393: strcpy(*strp+current, rest);
! 394: free(rest);
! 395: }
! 396:
1.1 maekawa 397: screen_ok = FALSE;
398: }
399:
400: #else /* VMS || PIPES || ATARI && PUREC */
401:
1.1.1.3 ! ohara 402: static void substitute(strp, str_lenp, current)
! 403: char **strp;
! 404: int *str_lenp;
! 405: int current;
1.1 maekawa 406: {
407: char line[100];
408:
409: sprintf(line, "substitution not supported by %s", OS);
410: int_error(line, t_num);
411: }
412:
413: #endif /* unix || VMS || PIPES || ATARI && PUREC */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>