OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltParse.c
1 /*
2  * tclParse.c --
3  *
4  *      Contains a collection of procedures that are used to parse Tcl
5  *      commands or parts of commands (like quoted strings or nested
6  *      sub-commands).  
7  *
8  *      Since Tcl 8.1.0 these routines have been replaced by ones that
9  *      generate byte-codes.  But since these routines are used in
10  *      vector expressions, where no such byte-compilation is
11  *      necessary, I now include them.  In fact, the byte-compiled
12  *      versions would be slower since the compiled code typically
13  *      runs only one time.
14  *
15  * Copyright (c) 1987-1993 The Regents of the University of California.
16  * Copyright (c) 19941998 Sun Microsystems, Inc.
17  * 
18  */
19
20 #include <bltInt.h>
21
22 #if (TCL_VERSION_NUMBER >= _VERSION(8,1,0))
23 #include "bltInterp.h"
24
25 /*
26  * A table used to classify input characters to assist in parsing
27  * Tcl commands.  The table should be indexed with a signed character
28  * using the CHAR_TYPE macro.  The character may have a negative
29  * value.  The CHAR_TYPE macro takes a pointer to a signed character
30  * and a pointer to the last character in the source string.  If the
31  * src pointer is pointing at the terminating null of the string,
32  * CHAR_TYPE returns TCL_COMMAND_END.
33  */
34
35 #define STATIC_STRING_SPACE     150
36 #define UCHAR(c)                ((unsigned char) (c))
37 #define TCL_NORMAL              0x01
38 #define TCL_SPACE               0x02
39 #define TCL_COMMAND_END         0x04
40 #define TCL_QUOTE               0x08
41 #define TCL_OPEN_BRACKET        0x10
42 #define TCL_OPEN_BRACE          0x20
43 #define TCL_CLOSE_BRACE         0x40
44 #define TCL_BACKSLASH           0x80
45 #define TCL_DOLLAR              0x00
46
47 /*
48  * The following table assigns a type to each character. Only types
49  * meaningful to Tcl parsing are represented here. The table is
50  * designed to be referenced with either signed or unsigned characters,
51  * so it has 384 entries. The first 128 entries correspond to negative
52  * character values, the next 256 correspond to positive character
53  * values. The last 128 entries are identical to the first 128. The
54  * table is always indexed with a 128-byte offset (the 128th entry
55  * corresponds to a 0 character value).
56  */
57
58 static unsigned char tclTypeTable[] =
59 {
60  /*
61      * Negative character values, from -128 to -1:
62      */
63
64     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
65     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
66     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
67     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
68     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
69     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
70     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
71     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
72     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
73     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
74     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
75     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
76     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
77     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
78     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
79     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
80     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
81     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
82     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
83     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
84     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
85     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
86     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
87     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
88     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
89     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
90     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
91     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
92     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
93     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
94     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
95     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
96
97  /*
98      * Positive character values, from 0-127:
99      */
100
101     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
102     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
103     TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE,
104     TCL_SPACE, TCL_SPACE, TCL_NORMAL, TCL_NORMAL,
105     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
106     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
107     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
108     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
109     TCL_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL,
110     TCL_DOLLAR, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
111     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
112     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
113     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
114     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
115     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_COMMAND_END,
116     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
117     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
118     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
119     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
120     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
121     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
122     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
123     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACKET,
124     TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL,
125     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
126     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
127     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
128     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
129     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
130     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
131     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE,
132     TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL,
133
134  /*
135      * Large unsigned character values, from 128-255:
136      */
137
138     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
139     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
140     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
141     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
142     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
143     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
144     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
145     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
146     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
147     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
148     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
149     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
150     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
151     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
152     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
153     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
154     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
155     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
156     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
157     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
158     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
159     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
160     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
161     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
162     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
163     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
164     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
165     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
166     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
167     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
168     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
169     TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
170 };
171
172 #define CHAR_TYPE(src,last) \
173         (((src)==(last))?TCL_COMMAND_END:(tclTypeTable+128)[(int)*(src)])
174
175 /*
176  *--------------------------------------------------------------
177  *
178  * Blt_ParseNestedCmd --
179  *
180  *      This procedure parses a nested Tcl command between
181  *      brackets, returning the result of the command.
182  *
183  * Results:
184  *      The return value is a standard Tcl result, which is
185  *      TCL_OK unless there was an error while executing the
186  *      nested command.  If an error occurs then interp->result
187  *      contains a standard error message.  *TermPtr is filled
188  *      in with the address of the character just after the
189  *      last one processed;  this is usually the character just
190  *      after the matching close-bracket, or the null character
191  *      at the end of the string if the close-bracket was missing
192  *      (a missing close bracket is an error).  The result returned
193  *      by the command is stored in standard fashion in *parsePtr,
194  *      null-terminated, with parsePtr->next pointing to the null
195  *      character.
196  *
197  * Side effects:
198  *      The storage space at *parsePtr may be expanded.
199  *
200  *--------------------------------------------------------------
201  */
202 int
203 Blt_ParseNestedCmd(interp, string, flags, termPtr, parsePtr)
204     Tcl_Interp *interp;         /* Interpreter to use for nested command
205                                  * evaluations and error messages. */
206     char *string;               /* Character just after opening bracket. */
207     int flags;                  /* Flags to pass to nested Tcl_Eval. */
208     char **termPtr;             /* Store address of terminating character
209                                  * here. */
210     ParseValue *parsePtr;       /* Information about where to place
211                                  * result of command. */
212 {
213     int result, length, shortfall;
214     Interp *iPtr = (Interp *) interp;
215
216     iPtr->evalFlags = flags | TCL_BRACKET_TERM;
217     result = Tcl_Eval(interp, string);
218     *termPtr = (string + iPtr->termOffset);
219     if (result != TCL_OK) {
220         /*
221          * The increment below results in slightly cleaner message in
222          * the errorInfo variable (the close-bracket will appear).
223          */
224
225         if (**termPtr == ']') {
226             *termPtr += 1;
227         }
228         return result;
229     }
230     (*termPtr) += 1;
231     length = strlen(iPtr->result);
232     shortfall = length + 1 - (parsePtr->end - parsePtr->next);
233     if (shortfall > 0) {
234         (*parsePtr->expandProc) (parsePtr, shortfall);
235     }
236     strcpy(parsePtr->next, iPtr->result);
237     parsePtr->next += length;
238
239     Tcl_FreeResult(interp);
240     iPtr->result = iPtr->resultSpace;
241     iPtr->resultSpace[0] = '\0';
242     return TCL_OK;
243 }
244 \f
245 /*
246  *--------------------------------------------------------------
247  *
248  * Blt_ParseBraces --
249  *
250  *      This procedure scans the information between matching
251  *      curly braces.
252  *
253  * Results:
254  *      The return value is a standard Tcl result, which is
255  *      TCL_OK unless there was an error while parsing string.
256  *      If an error occurs then interp->result contains a
257  *      standard error message.  *TermPtr is filled
258  *      in with the address of the character just after the
259  *      last one successfully processed;  this is usually the
260  *      character just after the matching close-brace.  The
261  *      information between curly braces is stored in standard
262  *      fashion in *parsePtr, null-terminated with parsePtr->next
263  *      pointing to the terminating null character.
264  *
265  * Side effects:
266  *      The storage space at *parsePtr may be expanded.
267  *
268  *--------------------------------------------------------------
269  */
270
271 int
272 Blt_ParseBraces(interp, string, termPtr, parsePtr)
273     Tcl_Interp *interp;         /* Interpreter to use for nested command
274                                  * evaluations and error messages. */
275     char *string;               /* Character just after opening bracket. */
276     char **termPtr;             /* Store address of terminating character
277                                  * here. */
278     ParseValue *parsePtr;       /* Information about where to place
279                                  * result of command. */
280 {
281     int level;
282     register char *src, *dest, *end;
283     register char c;
284     char *lastChar = string + strlen(string);
285
286     src = string;
287     dest = parsePtr->next;
288     end = parsePtr->end;
289     level = 1;
290
291     /*
292      * Copy the characters one at a time to the result area, stopping
293      * when the matching close-brace is found.
294      */
295
296     for (;;) {
297         c = *src;
298         src++;
299
300         if (dest == end) {
301             parsePtr->next = dest;
302             (*parsePtr->expandProc) (parsePtr, 20);
303             dest = parsePtr->next;
304             end = parsePtr->end;
305         }
306         *dest = c;
307         dest++;
308
309         if (CHAR_TYPE(src - 1, lastChar) == TCL_NORMAL) {
310             continue;
311         } else if (c == '{') {
312             level++;
313         } else if (c == '}') {
314             level--;
315             if (level == 0) {
316                 dest--;         /* Don't copy the last close brace. */
317                 break;
318             }
319         } else if (c == '\\') {
320             int count;
321
322             /*
323              * Must always squish out backslash-newlines, even when in
324              * braces.  This is needed so that this sequence can appear
325              * anywhere in a command, such as the middle of an expression.
326              */
327
328             if (*src == '\n') {
329                 dest[-1] = Tcl_Backslash(src - 1, &count);
330                 src += count - 1;
331             } else {
332                 Tcl_Backslash(src - 1, &count);
333                 while (count > 1) {
334                     if (dest == end) {
335                         parsePtr->next = dest;
336                         (*parsePtr->expandProc) (parsePtr, 20);
337                         dest = parsePtr->next;
338                         end = parsePtr->end;
339                     }
340                     *dest = *src;
341                     dest++;
342                     src++;
343                     count--;
344                 }
345             }
346         } else if (c == '\0') {
347             Tcl_AppendResult(interp, "missing close-brace", (char *)NULL);
348             *termPtr = string - 1;
349             return TCL_ERROR;
350         }
351     }
352
353     *dest = '\0';
354     parsePtr->next = dest;
355     *termPtr = src;
356     return TCL_OK;
357 }
358 \f
359 /*
360  *--------------------------------------------------------------
361  *
362  * Blt_ExpandParseValue --
363  *
364  *      This procedure is commonly used as the value of the
365  *      expandProc in a ParseValue.  It uses malloc to allocate
366  *      more space for the result of a parse.
367  *
368  * Results:
369  *      The buffer space in *parsePtr is reallocated to something
370  *      larger, and if parsePtr->clientData is non-zero the old
371  *      buffer is freed.  Information is copied from the old
372  *      buffer to the new one.
373  *
374  * Side effects:
375  *      None.
376  *
377  *--------------------------------------------------------------
378  */
379 void
380 Blt_ExpandParseValue(parsePtr, needed)
381     ParseValue *parsePtr;       /* Information about buffer that
382                                  * must be expanded.  If the clientData
383                                  * in the structure is non-zero, it
384                                  * means that the current buffer is
385                                  * dynamically allocated. */
386     int needed;                 /* Minimum amount of additional space
387                                  * to allocate. */
388 {
389     int size;
390     char *buffer;
391
392     /*
393      * Either double the size of the buffer or add enough new space
394      * to meet the demand, whichever produces a larger new buffer.
395      */
396     size = (parsePtr->end - parsePtr->buffer) + 1;
397     if (size < needed) {
398         size += needed;
399     } else {
400         size += size;
401     }
402     buffer = Blt_Malloc((unsigned int)size);
403
404     /*
405      * Copy from old buffer to new, free old buffer if needed, and
406      * mark new buffer as malloc-ed.
407      */
408     memcpy((VOID *) buffer, (VOID *) parsePtr->buffer,
409         (size_t) (parsePtr->next - parsePtr->buffer));
410     parsePtr->next = buffer + (parsePtr->next - parsePtr->buffer);
411     if (parsePtr->clientData != 0) {
412         Blt_Free(parsePtr->buffer);
413     }
414     parsePtr->buffer = buffer;
415     parsePtr->end = buffer + size - 1;
416     parsePtr->clientData = (ClientData)1;
417 }
418
419 /*
420  *--------------------------------------------------------------
421  *
422  * Blt_ParseQuotes --
423  *
424  *      This procedure parses a double-quoted string such as a
425  *      quoted Tcl command argument or a quoted value in a Tcl
426  *      expression.  This procedure is also used to parse array
427  *      element names within parentheses, or anything else that
428  *      needs all the substitutions that happen in quotes.
429  *
430  * Results:
431  *      The return value is a standard Tcl result, which is
432  *      TCL_OK unless there was an error while parsing the
433  *      quoted string.  If an error occurs then interp->result
434  *      contains a standard error message.  *TermPtr is filled
435  *      in with the address of the character just after the
436  *      last one successfully processed;  this is usually the
437  *      character just after the matching close-quote.  The
438  *      fully-substituted contents of the quotes are stored in
439  *      standard fashion in *parsePtr, null-terminated with
440  *      parsePtr->next pointing to the terminating null character.
441  *
442  * Side effects:
443  *      The buffer space in parsePtr may be enlarged by calling its
444  *      expandProc.
445  *
446  *--------------------------------------------------------------
447  */
448 int
449 Blt_ParseQuotes(interp, string, termChar, flags, termPtr, parsePtr)
450     Tcl_Interp *interp;         /* Interpreter to use for nested command
451                                  * evaluations and error messages. */
452     char *string;               /* Character just after opening double-
453                                  * quote. */
454     int termChar;               /* Character that terminates "quoted" string
455                                  * (usually double-quote, but sometimes
456                                  * right-paren or something else). */
457     int flags;                  /* Flags to pass to nested Tcl_Eval calls. */
458     char **termPtr;             /* Store address of terminating character
459                                  * here. */
460     ParseValue *parsePtr;       /* Information about where to place
461                                  * fully-substituted result of parse. */
462 {
463     register char *src, *dest, c;
464     char *lastChar = string + strlen(string);
465
466     src = string;
467     dest = parsePtr->next;
468
469     for (;;) {
470         if (dest == parsePtr->end) {
471             /*
472              * Target buffer space is about to run out.  Make more space.
473              */
474             parsePtr->next = dest;
475             (*parsePtr->expandProc) (parsePtr, 1);
476             dest = parsePtr->next;
477         }
478         c = *src;
479         src++;
480         if (c == termChar) {
481             *dest = '\0';
482             parsePtr->next = dest;
483             *termPtr = src;
484             return TCL_OK;
485         } else if (CHAR_TYPE(src - 1, lastChar) == TCL_NORMAL) {
486           copy:
487             *dest = c;
488             dest++;
489             continue;
490         } else if (c == '$') {
491             int length;
492             CONST char *value;
493
494             value = Tcl_ParseVar(interp, src - 1, termPtr);
495             if (value == NULL) {
496                 return TCL_ERROR;
497             }
498             src = *termPtr;
499             length = strlen(value);
500             if ((parsePtr->end - dest) <= length) {
501                 parsePtr->next = dest;
502                 (*parsePtr->expandProc) (parsePtr, length);
503                 dest = parsePtr->next;
504             }
505             strcpy(dest, value);
506             dest += length;
507             continue;
508         } else if (c == '[') {
509             int result;
510
511             parsePtr->next = dest;
512             result = Blt_ParseNestedCmd(interp, src, flags, termPtr, parsePtr);
513             if (result != TCL_OK) {
514                 return result;
515             }
516             src = *termPtr;
517             dest = parsePtr->next;
518             continue;
519         } else if (c == '\\') {
520             int nRead;
521
522             src--;
523             *dest = Tcl_Backslash(src, &nRead);
524             dest++;
525             src += nRead;
526             continue;
527         } else if (c == '\0') {
528             char buf[30];
529
530             Tcl_ResetResult(interp);
531             sprintf(buf, "missing %c", termChar);
532             Tcl_SetResult(interp, buf, TCL_VOLATILE);
533             *termPtr = string - 1;
534             return TCL_ERROR;
535         } else {
536             goto copy;
537         }
538     }
539 }
540
541 #endif /* TCL_VERSION_NUMBER >= _VERSION(8,1,0) */