Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libtksh/tcl/tclParse.c
1810 views
1
/*
2
* tclParse.c --
3
*
4
* This file contains a collection of procedures that are used
5
* to parse Tcl commands or parts of commands (like quoted
6
* strings or nested sub-commands).
7
*
8
* Copyright (c) 1987-1993 The Regents of the University of California.
9
* Copyright (c) 1994-1996 Sun Microsystems, Inc.
10
*
11
* See the file "license.terms" for information on usage and redistribution
12
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
*
14
* SCCS: @(#) tclParse.c 1.51 96/09/06 09:47:29
15
*/
16
17
#include "tclInt.h"
18
#include "tclPort.h"
19
20
/*
21
* The following table assigns a type to each character. Only types
22
* meaningful to Tcl parsing are represented here. The table is
23
* designed to be referenced with either signed or unsigned characters,
24
* so it has 384 entries. The first 128 entries correspond to negative
25
* character values, the next 256 correspond to positive character
26
* values. The last 128 entries are identical to the first 128. The
27
* table is always indexed with a 128-byte offset (the 128th entry
28
* corresponds to a 0 character value).
29
*/
30
31
char tclTypeTable[] = {
32
/*
33
* Negative character values, from -128 to -1:
34
*/
35
36
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
37
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
38
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
39
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
40
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
41
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
42
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
43
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
44
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
45
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
46
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
47
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
48
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
49
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
50
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
51
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
52
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
53
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
54
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
55
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
56
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
57
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
58
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
59
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
60
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
61
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
62
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
63
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
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
69
/*
70
* Positive character values, from 0-127:
71
*/
72
73
TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
74
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
75
TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE,
76
TCL_SPACE, TCL_SPACE, 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_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL,
82
TCL_DOLLAR, 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_COMMAND_END,
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_OPEN_BRACKET,
96
TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL,
97
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
98
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
99
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
100
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
101
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
102
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
103
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE,
104
TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL,
105
106
/*
107
* Large unsigned character values, from 128-255:
108
*/
109
110
TCL_NORMAL, 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_NORMAL,
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_NORMAL,
124
TCL_NORMAL, TCL_NORMAL, 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_NORMAL,
132
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
133
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
134
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
135
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
136
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
137
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
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
};
143
144
/*
145
* Function prototypes for procedures local to this file:
146
*/
147
148
static char * QuoteEnd _ANSI_ARGS_((char *string, int term));
149
static char * ScriptEnd _ANSI_ARGS_((char *p, int nested));
150
static char * VarNameEnd _ANSI_ARGS_((char *string));
151
152
/*
153
*----------------------------------------------------------------------
154
*
155
* Tcl_Backslash --
156
*
157
* Figure out how to handle a backslash sequence.
158
*
159
* Results:
160
* The return value is the character that should be substituted
161
* in place of the backslash sequence that starts at src. If
162
* readPtr isn't NULL then it is filled in with a count of the
163
* number of characters in the backslash sequence.
164
*
165
* Side effects:
166
* None.
167
*
168
*----------------------------------------------------------------------
169
*/
170
171
char
172
Tcl_Backslash(src, readPtr)
173
char *src; /* Points to the backslash character of
174
* a backslash sequence. */
175
int *readPtr; /* Fill in with number of characters read
176
* from src, unless NULL. */
177
{
178
register char *p = src+1;
179
char result;
180
int count;
181
182
count = 2;
183
184
switch (*p) {
185
/*
186
* Note: in the conversions below, use absolute values (e.g.,
187
* 0xa) rather than symbolic values (e.g. \n) that get converted
188
* by the compiler. It's possible that compilers on some
189
* platforms will do the symbolic conversions differently, which
190
* could result in non-portable Tcl scripts.
191
*/
192
193
case 'a':
194
result = 0x7;
195
break;
196
case 'b':
197
result = 0x8;
198
break;
199
case 'f':
200
result = 0xc;
201
break;
202
case 'n':
203
result = 0xa;
204
break;
205
case 'r':
206
result = 0xd;
207
break;
208
case 't':
209
result = 0x9;
210
break;
211
case 'v':
212
result = 0xb;
213
break;
214
case 'x':
215
if (isxdigit(UCHAR(p[1]))) {
216
char *end;
217
218
result = (char) strtoul(p+1, &end, 16);
219
count = end - src;
220
} else {
221
count = 2;
222
result = 'x';
223
}
224
break;
225
case '\n':
226
do {
227
p++;
228
} while ((*p == ' ') || (*p == '\t'));
229
result = ' ';
230
count = p - src;
231
break;
232
case 0:
233
result = '\\';
234
count = 1;
235
break;
236
default:
237
if (isdigit(UCHAR(*p))) {
238
result = (char)(*p - '0');
239
p++;
240
if (!isdigit(UCHAR(*p))) {
241
break;
242
}
243
count = 3;
244
result = (char)((result << 3) + (*p - '0'));
245
p++;
246
if (!isdigit(UCHAR(*p))) {
247
break;
248
}
249
count = 4;
250
result = (char)((result << 3) + (*p - '0'));
251
break;
252
}
253
result = *p;
254
count = 2;
255
break;
256
}
257
258
if (readPtr != NULL) {
259
*readPtr = count;
260
}
261
return result;
262
}
263
264
/*
265
*--------------------------------------------------------------
266
*
267
* TclParseQuotes --
268
*
269
* This procedure parses a double-quoted string such as a
270
* quoted Tcl command argument or a quoted value in a Tcl
271
* expression. This procedure is also used to parse array
272
* element names within parentheses, or anything else that
273
* needs all the substitutions that happen in quotes.
274
*
275
* Results:
276
* The return value is a standard Tcl result, which is
277
* TCL_OK unless there was an error while parsing the
278
* quoted string. If an error occurs then interp->result
279
* contains a standard error message. *TermPtr is filled
280
* in with the address of the character just after the
281
* last one successfully processed; this is usually the
282
* character just after the matching close-quote. The
283
* fully-substituted contents of the quotes are stored in
284
* standard fashion in *pvPtr, null-terminated with
285
* pvPtr->next pointing to the terminating null character.
286
*
287
* Side effects:
288
* The buffer space in pvPtr may be enlarged by calling its
289
* expandProc.
290
*
291
*--------------------------------------------------------------
292
*/
293
294
int
295
TclParseQuotes(interp, string, termChar, flags, termPtr, pvPtr)
296
Tcl_Interp *interp; /* Interpreter to use for nested command
297
* evaluations and error messages. */
298
char *string; /* Character just after opening double-
299
* quote. */
300
int termChar; /* Character that terminates "quoted" string
301
* (usually double-quote, but sometimes
302
* right-paren or something else). */
303
int flags; /* Flags to pass to nested Tcl_Eval calls. */
304
char **termPtr; /* Store address of terminating character
305
* here. */
306
ParseValue *pvPtr; /* Information about where to place
307
* fully-substituted result of parse. */
308
{
309
register char *src, *dst, c;
310
311
src = string;
312
dst = pvPtr->next;
313
314
while (1) {
315
if (dst == pvPtr->end) {
316
/*
317
* Target buffer space is about to run out. Make more space.
318
*/
319
320
pvPtr->next = dst;
321
(*pvPtr->expandProc)(pvPtr, 1);
322
dst = pvPtr->next;
323
}
324
325
c = *src;
326
src++;
327
if (c == termChar) {
328
*dst = '\0';
329
pvPtr->next = dst;
330
*termPtr = src;
331
return TCL_OK;
332
} else if (CHAR_TYPE(c) == TCL_NORMAL) {
333
copy:
334
*dst = c;
335
dst++;
336
continue;
337
} else if (c == '$') {
338
int length;
339
char *value;
340
341
value = Tcl_ParseVar(interp, src-1, termPtr);
342
if (value == NULL) {
343
return TCL_ERROR;
344
}
345
src = *termPtr;
346
length = strlen(value);
347
if ((pvPtr->end - dst) <= length) {
348
pvPtr->next = dst;
349
(*pvPtr->expandProc)(pvPtr, length);
350
dst = pvPtr->next;
351
}
352
strcpy(dst, value);
353
dst += length;
354
continue;
355
} else if (c == '[') {
356
int result;
357
358
pvPtr->next = dst;
359
result = TclParseNestedCmd(interp, src, flags, termPtr, pvPtr);
360
if (result != TCL_OK) {
361
return result;
362
}
363
src = *termPtr;
364
dst = pvPtr->next;
365
continue;
366
} else if (c == '\\') {
367
int numRead;
368
369
src--;
370
*dst = Tcl_Backslash(src, &numRead);
371
dst++;
372
src += numRead;
373
continue;
374
} else if (c == '\0') {
375
Tcl_ResetResult(interp);
376
sprintf(interp->result, "missing %c", termChar);
377
*termPtr = string-1;
378
return TCL_ERROR;
379
} else {
380
goto copy;
381
}
382
}
383
}
384
385
/*
386
*--------------------------------------------------------------
387
*
388
* TclParseNestedCmd --
389
*
390
* This procedure parses a nested Tcl command between
391
* brackets, returning the result of the command.
392
*
393
* Results:
394
* The return value is a standard Tcl result, which is
395
* TCL_OK unless there was an error while executing the
396
* nested command. If an error occurs then interp->result
397
* contains a standard error message. *TermPtr is filled
398
* in with the address of the character just after the
399
* last one processed; this is usually the character just
400
* after the matching close-bracket, or the null character
401
* at the end of the string if the close-bracket was missing
402
* (a missing close bracket is an error). The result returned
403
* by the command is stored in standard fashion in *pvPtr,
404
* null-terminated, with pvPtr->next pointing to the null
405
* character.
406
*
407
* Side effects:
408
* The storage space at *pvPtr may be expanded.
409
*
410
*--------------------------------------------------------------
411
*/
412
413
int
414
TclParseNestedCmd(interp, string, flags, termPtr, pvPtr)
415
Tcl_Interp *interp; /* Interpreter to use for nested command
416
* evaluations and error messages. */
417
char *string; /* Character just after opening bracket. */
418
int flags; /* Flags to pass to nested Tcl_Eval. */
419
char **termPtr; /* Store address of terminating character
420
* here. */
421
register ParseValue *pvPtr; /* Information about where to place
422
* result of command. */
423
{
424
int result, length, shortfall;
425
Interp *iPtr = (Interp *) interp;
426
427
iPtr->evalFlags = flags | TCL_BRACKET_TERM;
428
result = Tcl_Eval(interp, string);
429
*termPtr = iPtr->termPtr;
430
if (result != TCL_OK) {
431
/*
432
* The increment below results in slightly cleaner message in
433
* the errorInfo variable (the close-bracket will appear).
434
*/
435
436
if (**termPtr == ']') {
437
*termPtr += 1;
438
}
439
return result;
440
}
441
(*termPtr) += 1;
442
length = strlen(iPtr->result);
443
shortfall = length + 1 - (pvPtr->end - pvPtr->next);
444
if (shortfall > 0) {
445
(*pvPtr->expandProc)(pvPtr, shortfall);
446
}
447
strcpy(pvPtr->next, iPtr->result);
448
pvPtr->next += length;
449
Tcl_FreeResult(iPtr);
450
iPtr->result = iPtr->resultSpace;
451
iPtr->resultSpace[0] = '\0';
452
return TCL_OK;
453
}
454
455
/*
456
*--------------------------------------------------------------
457
*
458
* TclParseBraces --
459
*
460
* This procedure scans the information between matching
461
* curly braces.
462
*
463
* Results:
464
* The return value is a standard Tcl result, which is
465
* TCL_OK unless there was an error while parsing string.
466
* If an error occurs then interp->result contains a
467
* standard error message. *TermPtr is filled
468
* in with the address of the character just after the
469
* last one successfully processed; this is usually the
470
* character just after the matching close-brace. The
471
* information between curly braces is stored in standard
472
* fashion in *pvPtr, null-terminated with pvPtr->next
473
* pointing to the terminating null character.
474
*
475
* Side effects:
476
* The storage space at *pvPtr may be expanded.
477
*
478
*--------------------------------------------------------------
479
*/
480
481
int
482
TclParseBraces(interp, string, termPtr, pvPtr)
483
Tcl_Interp *interp; /* Interpreter to use for nested command
484
* evaluations and error messages. */
485
char *string; /* Character just after opening bracket. */
486
char **termPtr; /* Store address of terminating character
487
* here. */
488
register ParseValue *pvPtr; /* Information about where to place
489
* result of command. */
490
{
491
int level;
492
register char *src, *dst, *end;
493
register char c;
494
495
src = string;
496
dst = pvPtr->next;
497
end = pvPtr->end;
498
level = 1;
499
500
/*
501
* Copy the characters one at a time to the result area, stopping
502
* when the matching close-brace is found.
503
*/
504
505
while (1) {
506
c = *src;
507
src++;
508
if (dst == end) {
509
pvPtr->next = dst;
510
(*pvPtr->expandProc)(pvPtr, 20);
511
dst = pvPtr->next;
512
end = pvPtr->end;
513
}
514
*dst = c;
515
dst++;
516
if (CHAR_TYPE(c) == TCL_NORMAL) {
517
continue;
518
} else if (c == '{') {
519
level++;
520
} else if (c == '}') {
521
level--;
522
if (level == 0) {
523
dst--; /* Don't copy the last close brace. */
524
break;
525
}
526
} else if (c == '\\') {
527
int count;
528
529
/*
530
* Must always squish out backslash-newlines, even when in
531
* braces. This is needed so that this sequence can appear
532
* anywhere in a command, such as the middle of an expression.
533
*/
534
535
if (*src == '\n') {
536
dst[-1] = Tcl_Backslash(src-1, &count);
537
src += count - 1;
538
} else {
539
(void) Tcl_Backslash(src-1, &count);
540
while (count > 1) {
541
if (dst == end) {
542
pvPtr->next = dst;
543
(*pvPtr->expandProc)(pvPtr, 20);
544
dst = pvPtr->next;
545
end = pvPtr->end;
546
}
547
*dst = *src;
548
dst++;
549
src++;
550
count--;
551
}
552
}
553
} else if (c == '\0') {
554
Tcl_SetResult(interp, "missing close-brace", TCL_STATIC);
555
*termPtr = string-1;
556
return TCL_ERROR;
557
}
558
}
559
560
*dst = '\0';
561
pvPtr->next = dst;
562
*termPtr = src;
563
return TCL_OK;
564
}
565
566
/*
567
*--------------------------------------------------------------
568
*
569
* TclParseWords --
570
*
571
* This procedure parses one or more words from a command
572
* string and creates argv-style pointers to fully-substituted
573
* copies of those words.
574
*
575
* Results:
576
* The return value is a standard Tcl result.
577
*
578
* *argcPtr is modified to hold a count of the number of words
579
* successfully parsed, which may be 0. At most maxWords words
580
* will be parsed. If 0 <= *argcPtr < maxWords then it
581
* means that a command separator was seen. If *argcPtr
582
* is maxWords then it means that a command separator was
583
* not seen yet.
584
*
585
* *TermPtr is filled in with the address of the character
586
* just after the last one successfully processed in the
587
* last word. This is either the command terminator (if
588
* *argcPtr < maxWords), the character just after the last
589
* one in a word (if *argcPtr is maxWords), or the vicinity
590
* of an error (if the result is not TCL_OK).
591
*
592
* The pointers at *argv are filled in with pointers to the
593
* fully-substituted words, and the actual contents of the
594
* words are copied to the buffer at pvPtr.
595
*
596
* If an error occurrs then an error message is left in
597
* interp->result and the information at *argv, *argcPtr,
598
* and *pvPtr may be incomplete.
599
*
600
* Side effects:
601
* The buffer space in pvPtr may be enlarged by calling its
602
* expandProc.
603
*
604
*--------------------------------------------------------------
605
*/
606
607
int
608
TclParseWords(interp, string, flags, maxWords, termPtr, argcPtr, argv, pvPtr)
609
Tcl_Interp *interp; /* Interpreter to use for nested command
610
* evaluations and error messages. */
611
char *string; /* First character of word. */
612
int flags; /* Flags to control parsing (same values as
613
* passed to Tcl_Eval). */
614
int maxWords; /* Maximum number of words to parse. */
615
char **termPtr; /* Store address of terminating character
616
* here. */
617
int *argcPtr; /* Filled in with actual number of words
618
* parsed. */
619
char **argv; /* Store addresses of individual words here. */
620
register ParseValue *pvPtr; /* Information about where to place
621
* fully-substituted word. */
622
{
623
register char *src, *dst;
624
register char c;
625
int type, result, argc;
626
char *oldBuffer; /* Used to detect when pvPtr's buffer gets
627
* reallocated, so we can adjust all of the
628
* argv pointers. */
629
630
src = string;
631
oldBuffer = pvPtr->buffer;
632
dst = pvPtr->next;
633
for (argc = 0; argc < maxWords; argc++) {
634
argv[argc] = dst;
635
636
/*
637
* Skip leading space.
638
*/
639
640
skipSpace:
641
c = *src;
642
type = CHAR_TYPE(c);
643
while (type == TCL_SPACE) {
644
src++;
645
c = *src;
646
type = CHAR_TYPE(c);
647
}
648
649
/*
650
* Handle the normal case (i.e. no leading double-quote or brace).
651
*/
652
653
if (type == TCL_NORMAL) {
654
normalArg:
655
while (1) {
656
if (dst == pvPtr->end) {
657
/*
658
* Target buffer space is about to run out. Make
659
* more space.
660
*/
661
662
pvPtr->next = dst;
663
(*pvPtr->expandProc)(pvPtr, 1);
664
dst = pvPtr->next;
665
}
666
667
if (type == TCL_NORMAL) {
668
copy:
669
*dst = c;
670
dst++;
671
src++;
672
} else if (type == TCL_SPACE) {
673
goto wordEnd;
674
} else if (type == TCL_DOLLAR) {
675
int length;
676
char *value;
677
678
value = Tcl_ParseVar(interp, src, termPtr);
679
if (value == NULL) {
680
return TCL_ERROR;
681
}
682
src = *termPtr;
683
length = strlen(value);
684
if ((pvPtr->end - dst) <= length) {
685
pvPtr->next = dst;
686
(*pvPtr->expandProc)(pvPtr, length);
687
dst = pvPtr->next;
688
}
689
strcpy(dst, value);
690
dst += length;
691
} else if (type == TCL_COMMAND_END) {
692
if ((c == ']') && !(flags & TCL_BRACKET_TERM)) {
693
goto copy;
694
}
695
696
/*
697
* End of command; simulate a word-end first, so
698
* that the end-of-command can be processed as the
699
* first thing in a new word.
700
*/
701
702
goto wordEnd;
703
} else if (type == TCL_OPEN_BRACKET) {
704
pvPtr->next = dst;
705
result = TclParseNestedCmd(interp, src+1, flags, termPtr,
706
pvPtr);
707
if (result != TCL_OK) {
708
return result;
709
}
710
src = *termPtr;
711
dst = pvPtr->next;
712
} else if (type == TCL_BACKSLASH) {
713
int numRead;
714
715
*dst = Tcl_Backslash(src, &numRead);
716
717
/*
718
* The following special check allows a backslash-newline
719
* to be treated as a word-separator, as if the backslash
720
* and newline had been collapsed before command parsing
721
* began.
722
*/
723
724
if (src[1] == '\n') {
725
src += numRead;
726
goto wordEnd;
727
}
728
src += numRead;
729
dst++;
730
} else {
731
goto copy;
732
}
733
c = *src;
734
type = CHAR_TYPE(c);
735
}
736
} else {
737
738
/*
739
* Check for the end of the command.
740
*/
741
742
if (type == TCL_COMMAND_END) {
743
if (flags & TCL_BRACKET_TERM) {
744
if (c == '\0') {
745
Tcl_SetResult(interp, "missing close-bracket",
746
TCL_STATIC);
747
return TCL_ERROR;
748
}
749
} else {
750
if (c == ']') {
751
goto normalArg;
752
}
753
}
754
goto done;
755
}
756
757
/*
758
* Now handle the special cases: open braces, double-quotes,
759
* and backslash-newline.
760
*/
761
762
pvPtr->next = dst;
763
if (type == TCL_QUOTE) {
764
result = TclParseQuotes(interp, src+1, '"', flags,
765
termPtr, pvPtr);
766
} else if (type == TCL_OPEN_BRACE) {
767
result = TclParseBraces(interp, src+1, termPtr, pvPtr);
768
} else if ((type == TCL_BACKSLASH) && (src[1] == '\n')) {
769
/*
770
* This code is needed so that a backslash-newline at the
771
* very beginning of a word is treated as part of the white
772
* space between words and not as a space within the word.
773
*/
774
775
src += 2;
776
goto skipSpace;
777
} else {
778
goto normalArg;
779
}
780
if (result != TCL_OK) {
781
return result;
782
}
783
784
/*
785
* Back from quotes or braces; make sure that the terminating
786
* character was the end of the word.
787
*/
788
789
c = **termPtr;
790
if ((c == '\\') && ((*termPtr)[1] == '\n')) {
791
/*
792
* Line is continued on next line; the backslash-newline
793
* sequence turns into space, which is OK. No need to do
794
* anything here.
795
*/
796
} else {
797
type = CHAR_TYPE(c);
798
if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
799
if (*src == '"') {
800
Tcl_SetResult(interp,
801
"extra characters after close-quote",
802
TCL_STATIC);
803
} else {
804
Tcl_SetResult(interp,
805
"extra characters after close-brace",
806
TCL_STATIC);
807
}
808
return TCL_ERROR;
809
}
810
}
811
src = *termPtr;
812
dst = pvPtr->next;
813
}
814
815
/*
816
* We're at the end of a word, so add a null terminator. Then
817
* see if the buffer was re-allocated during this word. If so,
818
* update all of the argv pointers.
819
*/
820
821
wordEnd:
822
*dst = '\0';
823
dst++;
824
if (oldBuffer != pvPtr->buffer) {
825
int i;
826
827
for (i = 0; i <= argc; i++) {
828
argv[i] = pvPtr->buffer + (argv[i] - oldBuffer);
829
}
830
oldBuffer = pvPtr->buffer;
831
}
832
}
833
834
done:
835
pvPtr->next = dst;
836
*termPtr = src;
837
*argcPtr = argc;
838
return TCL_OK;
839
}
840
841
/*
842
*--------------------------------------------------------------
843
*
844
* TclExpandParseValue --
845
*
846
* This procedure is commonly used as the value of the
847
* expandProc in a ParseValue. It uses malloc to allocate
848
* more space for the result of a parse.
849
*
850
* Results:
851
* The buffer space in *pvPtr is reallocated to something
852
* larger, and if pvPtr->clientData is non-zero the old
853
* buffer is freed. Information is copied from the old
854
* buffer to the new one.
855
*
856
* Side effects:
857
* None.
858
*
859
*--------------------------------------------------------------
860
*/
861
862
void
863
TclExpandParseValue(pvPtr, needed)
864
register ParseValue *pvPtr; /* Information about buffer that
865
* must be expanded. If the clientData
866
* in the structure is non-zero, it
867
* means that the current buffer is
868
* dynamically allocated. */
869
int needed; /* Minimum amount of additional space
870
* to allocate. */
871
{
872
int newSpace;
873
char *new;
874
875
/*
876
* Either double the size of the buffer or add enough new space
877
* to meet the demand, whichever produces a larger new buffer.
878
*/
879
880
newSpace = (pvPtr->end - pvPtr->buffer) + 1;
881
if (newSpace < needed) {
882
newSpace += needed;
883
} else {
884
newSpace += newSpace;
885
}
886
new = (char *) ckalloc((unsigned) newSpace);
887
888
/*
889
* Copy from old buffer to new, free old buffer if needed, and
890
* mark new buffer as malloc-ed.
891
*/
892
893
memcpy((VOID *) new, (VOID *) pvPtr->buffer,
894
(size_t) (pvPtr->next - pvPtr->buffer));
895
pvPtr->next = new + (pvPtr->next - pvPtr->buffer);
896
if (pvPtr->clientData != 0) {
897
ckfree(pvPtr->buffer);
898
}
899
pvPtr->buffer = new;
900
pvPtr->end = new + newSpace - 1;
901
pvPtr->clientData = (ClientData) 1;
902
}
903
904
/*
905
*----------------------------------------------------------------------
906
*
907
* TclWordEnd --
908
*
909
* Given a pointer into a Tcl command, find the end of the next
910
* word of the command.
911
*
912
* Results:
913
* The return value is a pointer to the last character that's part
914
* of the word pointed to by "start". If the word doesn't end
915
* properly within the string then the return value is the address
916
* of the null character at the end of the string.
917
*
918
* Side effects:
919
* None.
920
*
921
*----------------------------------------------------------------------
922
*/
923
924
char *
925
TclWordEnd(start, nested, semiPtr)
926
char *start; /* Beginning of a word of a Tcl command. */
927
int nested; /* Zero means this is a top-level command.
928
* One means this is a nested command (close
929
* bracket is a word terminator). */
930
int *semiPtr; /* Set to 1 if word ends with a command-
931
* terminating semi-colon, zero otherwise.
932
* If NULL then ignored. */
933
{
934
register char *p;
935
int count;
936
937
if (semiPtr != NULL) {
938
*semiPtr = 0;
939
}
940
941
/*
942
* Skip leading white space (backslash-newline must be treated like
943
* white-space, except that it better not be the last thing in the
944
* command).
945
*/
946
947
for (p = start; ; p++) {
948
if (isspace(UCHAR(*p))) {
949
continue;
950
}
951
if ((p[0] == '\\') && (p[1] == '\n')) {
952
if (p[2] == 0) {
953
return p+2;
954
}
955
continue;
956
}
957
break;
958
}
959
960
/*
961
* Handle words beginning with a double-quote or a brace.
962
*/
963
964
if (*p == '"') {
965
p = QuoteEnd(p+1, '"');
966
if (*p == 0) {
967
return p;
968
}
969
p++;
970
} else if (*p == '{') {
971
int braces = 1;
972
while (braces != 0) {
973
p++;
974
while (*p == '\\') {
975
(void) Tcl_Backslash(p, &count);
976
p += count;
977
}
978
if (*p == '}') {
979
braces--;
980
} else if (*p == '{') {
981
braces++;
982
} else if (*p == 0) {
983
return p;
984
}
985
}
986
p++;
987
}
988
989
/*
990
* Handle words that don't start with a brace or double-quote.
991
* This code is also invoked if the word starts with a brace or
992
* double-quote and there is garbage after the closing brace or
993
* quote. This is an error as far as Tcl_Eval is concerned, but
994
* for here the garbage is treated as part of the word.
995
*/
996
997
while (1) {
998
if (*p == '[') {
999
p = ScriptEnd(p+1, 1);
1000
if (*p == 0) {
1001
return p;
1002
}
1003
p++;
1004
} else if (*p == '\\') {
1005
if (p[1] == '\n') {
1006
/*
1007
* Backslash-newline: it maps to a space character
1008
* that is a word separator, so the word ends just before
1009
* the backslash.
1010
*/
1011
1012
return p-1;
1013
}
1014
(void) Tcl_Backslash(p, &count);
1015
p += count;
1016
} else if (*p == '$') {
1017
p = VarNameEnd(p);
1018
if (*p == 0) {
1019
return p;
1020
}
1021
p++;
1022
} else if (*p == ';') {
1023
/*
1024
* Include the semi-colon in the word that is returned.
1025
*/
1026
1027
if (semiPtr != NULL) {
1028
*semiPtr = 1;
1029
}
1030
return p;
1031
} else if (isspace(UCHAR(*p))) {
1032
return p-1;
1033
} else if ((*p == ']') && nested) {
1034
return p-1;
1035
} else if (*p == 0) {
1036
if (nested) {
1037
/*
1038
* Nested commands can't end because of the end of the
1039
* string.
1040
*/
1041
return p;
1042
}
1043
return p-1;
1044
} else {
1045
p++;
1046
}
1047
}
1048
}
1049
1050
/*
1051
*----------------------------------------------------------------------
1052
*
1053
* QuoteEnd --
1054
*
1055
* Given a pointer to a string that obeys the parsing conventions
1056
* for quoted things in Tcl, find the end of that quoted thing.
1057
* The actual thing may be a quoted argument or a parenthesized
1058
* index name.
1059
*
1060
* Results:
1061
* The return value is a pointer to the last character that is
1062
* part of the quoted string (i.e the character that's equal to
1063
* term). If the quoted string doesn't terminate properly then
1064
* the return value is a pointer to the null character at the
1065
* end of the string.
1066
*
1067
* Side effects:
1068
* None.
1069
*
1070
*----------------------------------------------------------------------
1071
*/
1072
1073
static char *
1074
QuoteEnd(string, term)
1075
char *string; /* Pointer to character just after opening
1076
* "quote". */
1077
int term; /* This character will terminate the
1078
* quoted string (e.g. '"' or ')'). */
1079
{
1080
register char *p = string;
1081
int count;
1082
1083
while (*p != term) {
1084
if (*p == '\\') {
1085
(void) Tcl_Backslash(p, &count);
1086
p += count;
1087
} else if (*p == '[') {
1088
for (p++; *p != ']'; p++) {
1089
p = TclWordEnd(p, 1, (int *) NULL);
1090
if (*p == 0) {
1091
return p;
1092
}
1093
}
1094
p++;
1095
} else if (*p == '$') {
1096
p = VarNameEnd(p);
1097
if (*p == 0) {
1098
return p;
1099
}
1100
p++;
1101
} else if (*p == 0) {
1102
return p;
1103
} else {
1104
p++;
1105
}
1106
}
1107
return p-1;
1108
}
1109
1110
/*
1111
*----------------------------------------------------------------------
1112
*
1113
* VarNameEnd --
1114
*
1115
* Given a pointer to a variable reference using $-notation, find
1116
* the end of the variable name spec.
1117
*
1118
* Results:
1119
* The return value is a pointer to the last character that
1120
* is part of the variable name. If the variable name doesn't
1121
* terminate properly then the return value is a pointer to the
1122
* null character at the end of the string.
1123
*
1124
* Side effects:
1125
* None.
1126
*
1127
*----------------------------------------------------------------------
1128
*/
1129
1130
static char *
1131
VarNameEnd(string)
1132
char *string; /* Pointer to dollar-sign character. */
1133
{
1134
register char *p = string+1;
1135
1136
if (*p == '{') {
1137
for (p++; (*p != '}') && (*p != 0); p++) {
1138
/* Empty loop body. */
1139
}
1140
return p;
1141
}
1142
while (isalnum(UCHAR(*p)) || (*p == '_')) {
1143
p++;
1144
}
1145
if ((*p == '(') && (p != string+1)) {
1146
return QuoteEnd(p+1, ')');
1147
}
1148
return p-1;
1149
}
1150
1151
1152
/*
1153
*----------------------------------------------------------------------
1154
*
1155
* ScriptEnd --
1156
*
1157
* Given a pointer to the beginning of a Tcl script, find the end of
1158
* the script.
1159
*
1160
* Results:
1161
* The return value is a pointer to the last character that's part
1162
* of the script pointed to by "p". If the command doesn't end
1163
* properly within the string then the return value is the address
1164
* of the null character at the end of the string.
1165
*
1166
* Side effects:
1167
* None.
1168
*
1169
*----------------------------------------------------------------------
1170
*/
1171
1172
static char *
1173
ScriptEnd(p, nested)
1174
char *p; /* Script to check. */
1175
int nested; /* Zero means this is a top-level command.
1176
* One means this is a nested command (the
1177
* last character of the script must be
1178
* an unquoted ]). */
1179
{
1180
int commentOK = 1;
1181
int length;
1182
1183
while (1) {
1184
while (isspace(UCHAR(*p))) {
1185
if (*p == '\n') {
1186
commentOK = 1;
1187
}
1188
p++;
1189
}
1190
if ((*p == '#') && commentOK) {
1191
do {
1192
if (*p == '\\') {
1193
/*
1194
* If the script ends with backslash-newline, then
1195
* this command isn't complete.
1196
*/
1197
1198
if ((p[1] == '\n') && (p[2] == 0)) {
1199
return p+2;
1200
}
1201
Tcl_Backslash(p, &length);
1202
p += length;
1203
} else {
1204
p++;
1205
}
1206
} while ((*p != 0) && (*p != '\n'));
1207
continue;
1208
}
1209
p = TclWordEnd(p, nested, &commentOK);
1210
if (*p == 0) {
1211
return p;
1212
}
1213
p++;
1214
if (nested) {
1215
if (*p == ']') {
1216
return p;
1217
}
1218
} else {
1219
if (*p == 0) {
1220
return p-1;
1221
}
1222
}
1223
}
1224
}
1225
1226
/*
1227
*----------------------------------------------------------------------
1228
*
1229
* Tcl_ParseVar --
1230
*
1231
* Given a string starting with a $ sign, parse off a variable
1232
* name and return its value.
1233
*
1234
* Results:
1235
* The return value is the contents of the variable given by
1236
* the leading characters of string. If termPtr isn't NULL,
1237
* *termPtr gets filled in with the address of the character
1238
* just after the last one in the variable specifier. If the
1239
* variable doesn't exist, then the return value is NULL and
1240
* an error message will be left in interp->result.
1241
*
1242
* Side effects:
1243
* None.
1244
*
1245
*----------------------------------------------------------------------
1246
*/
1247
1248
char *
1249
Tcl_ParseVar(interp, string, termPtr)
1250
Tcl_Interp *interp; /* Context for looking up variable. */
1251
register char *string; /* String containing variable name.
1252
* First character must be "$". */
1253
char **termPtr; /* If non-NULL, points to word to fill
1254
* in with character just after last
1255
* one in the variable specifier. */
1256
1257
{
1258
char *name1, *name1End, c, *result;
1259
register char *name2;
1260
#define NUM_CHARS 200
1261
char copyStorage[NUM_CHARS];
1262
ParseValue pv;
1263
1264
/*
1265
* There are three cases:
1266
* 1. The $ sign is followed by an open curly brace. Then the variable
1267
* name is everything up to the next close curly brace, and the
1268
* variable is a scalar variable.
1269
* 2. The $ sign is not followed by an open curly brace. Then the
1270
* variable name is everything up to the next character that isn't
1271
* a letter, digit, or underscore. If the following character is an
1272
* open parenthesis, then the information between parentheses is
1273
* the array element name, which can include any of the substitutions
1274
* permissible between quotes.
1275
* 3. The $ sign is followed by something that isn't a letter, digit,
1276
* or underscore: in this case, there is no variable name, and "$"
1277
* is returned.
1278
*/
1279
1280
name2 = NULL;
1281
string++;
1282
if (*string == '{') {
1283
string++;
1284
name1 = string;
1285
while (*string != '}') {
1286
if (*string == 0) {
1287
Tcl_SetResult(interp, "missing close-brace for variable name",
1288
TCL_STATIC);
1289
if (termPtr != 0) {
1290
*termPtr = string;
1291
}
1292
return NULL;
1293
}
1294
string++;
1295
}
1296
name1End = string;
1297
string++;
1298
} else {
1299
name1 = string;
1300
while (isalnum(UCHAR(*string)) || (*string == '_')) {
1301
string++;
1302
}
1303
if (string == name1) {
1304
if (termPtr != 0) {
1305
*termPtr = string;
1306
}
1307
return "$";
1308
}
1309
name1End = string;
1310
if (*string == '(') {
1311
char *end;
1312
1313
/*
1314
* Perform substitutions on the array element name, just as
1315
* is done for quotes.
1316
*/
1317
1318
pv.buffer = pv.next = copyStorage;
1319
pv.end = copyStorage + NUM_CHARS - 1;
1320
pv.expandProc = TclExpandParseValue;
1321
pv.clientData = (ClientData) NULL;
1322
if (TclParseQuotes(interp, string+1, ')', 0, &end, &pv)
1323
!= TCL_OK) {
1324
char msg[200];
1325
int length;
1326
1327
length = string-name1;
1328
if (length > 100) {
1329
length = 100;
1330
}
1331
sprintf(msg, "\n (parsing index for array \"%.*s\")",
1332
length, name1);
1333
Tcl_AddErrorInfo(interp, msg);
1334
result = NULL;
1335
name2 = pv.buffer;
1336
if (termPtr != 0) {
1337
*termPtr = end;
1338
}
1339
goto done;
1340
}
1341
Tcl_ResetResult(interp);
1342
string = end;
1343
name2 = pv.buffer;
1344
}
1345
}
1346
if (termPtr != 0) {
1347
*termPtr = string;
1348
}
1349
1350
if (((Interp *) interp)->noEval) {
1351
return "";
1352
}
1353
c = *name1End;
1354
*name1End = 0;
1355
result = Tcl_GetVar2(interp, name1, name2, TCL_LEAVE_ERR_MSG);
1356
*name1End = c;
1357
1358
done:
1359
if ((name2 != NULL) && (pv.buffer != copyStorage)) {
1360
ckfree(pv.buffer);
1361
}
1362
return result;
1363
}
1364
1365
/*
1366
*----------------------------------------------------------------------
1367
*
1368
* Tcl_CommandComplete --
1369
*
1370
* Given a partial or complete Tcl command, this procedure
1371
* determines whether the command is complete in the sense
1372
* of having matched braces and quotes and brackets.
1373
*
1374
* Results:
1375
* 1 is returned if the command is complete, 0 otherwise.
1376
*
1377
* Side effects:
1378
* None.
1379
*
1380
*----------------------------------------------------------------------
1381
*/
1382
1383
int
1384
Tcl_CommandComplete(cmd)
1385
char *cmd; /* Command to check. */
1386
{
1387
char *p;
1388
1389
if (*cmd == 0) {
1390
return 1;
1391
}
1392
p = ScriptEnd(cmd, 0);
1393
return (*p != 0);
1394
}
1395
1396