Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libtksh/tcl/tclUtil.c
1810 views
1
/*
2
* tclUtil.c --
3
*
4
* This file contains utility procedures that are used by many Tcl
5
* commands.
6
*
7
* Copyright (c) 1987-1993 The Regents of the University of California.
8
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
9
*
10
* See the file "license.terms" for information on usage and redistribution
11
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
*
13
* SCCS: @(#) tclUtil.c 1.114 96/06/06 13:48:58
14
*/
15
16
#include "tclInt.h"
17
#include "tclPort.h"
18
19
/*
20
* The following values are used in the flags returned by Tcl_ScanElement
21
* and used by Tcl_ConvertElement. The value TCL_DONT_USE_BRACES is also
22
* defined in tcl.h; make sure its value doesn't overlap with any of the
23
* values below.
24
*
25
* TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in
26
* braces (e.g. it contains unmatched braces,
27
* or ends in a backslash character, or user
28
* just doesn't want braces); handle all
29
* special characters by adding backslashes.
30
* USE_BRACES - 1 means the string contains a special
31
* character that can be handled simply by
32
* enclosing the entire argument in braces.
33
* BRACES_UNMATCHED - 1 means that braces aren't properly matched
34
* in the argument.
35
*/
36
37
#define USE_BRACES 2
38
#define BRACES_UNMATCHED 4
39
40
/*
41
* Function prototypes for local procedures in this file:
42
*/
43
44
static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
45
int newSpace));
46
47
/*
48
*----------------------------------------------------------------------
49
*
50
* TclFindElement --
51
*
52
* Given a pointer into a Tcl list, locate the first (or next)
53
* element in the list.
54
*
55
* Results:
56
* The return value is normally TCL_OK, which means that the
57
* element was successfully located. If TCL_ERROR is returned
58
* it means that list didn't have proper list structure;
59
* interp->result contains a more detailed error message.
60
*
61
* If TCL_OK is returned, then *elementPtr will be set to point
62
* to the first element of list, and *nextPtr will be set to point
63
* to the character just after any white space following the last
64
* character that's part of the element. If this is the last argument
65
* in the list, then *nextPtr will point to the NULL character at the
66
* end of list. If sizePtr is non-NULL, *sizePtr is filled in with
67
* the number of characters in the element. If the element is in
68
* braces, then *elementPtr will point to the character after the
69
* opening brace and *sizePtr will not include either of the braces.
70
* If there isn't an element in the list, *sizePtr will be zero, and
71
* both *elementPtr and *termPtr will refer to the null character at
72
* the end of list. Note: this procedure does NOT collapse backslash
73
* sequences.
74
*
75
* Side effects:
76
* None.
77
*
78
*----------------------------------------------------------------------
79
*/
80
81
int
82
TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
83
Tcl_Interp *interp; /* Interpreter to use for error reporting.
84
* If NULL, then no error message is left
85
* after errors. */
86
register char *list; /* String containing Tcl list with zero
87
* or more elements (possibly in braces). */
88
char **elementPtr; /* Fill in with location of first significant
89
* character in first element of list. */
90
char **nextPtr; /* Fill in with location of character just
91
* after all white space following end of
92
* argument (i.e. next argument or end of
93
* list). */
94
int *sizePtr; /* If non-zero, fill in with size of
95
* element. */
96
int *bracePtr; /* If non-zero fill in with non-zero/zero
97
* to indicate that arg was/wasn't
98
* in braces. */
99
{
100
register char *p;
101
int openBraces = 0;
102
int inQuotes = 0;
103
int size;
104
105
/*
106
* Skim off leading white space and check for an opening brace or
107
* quote. Note: use of "isascii" below and elsewhere in this
108
* procedure is a temporary hack (7/27/90) because Mx uses characters
109
* with the high-order bit set for some things. This should probably
110
* be changed back eventually, or all of Tcl should call isascii.
111
*/
112
113
while (isspace(UCHAR(*list))) {
114
list++;
115
}
116
if (*list == '{') {
117
openBraces = 1;
118
list++;
119
} else if (*list == '"') {
120
inQuotes = 1;
121
list++;
122
}
123
if (bracePtr != 0) {
124
*bracePtr = openBraces;
125
}
126
p = list;
127
128
/*
129
* Find the end of the element (either a space or a close brace or
130
* the end of the string).
131
*/
132
133
while (1) {
134
switch (*p) {
135
136
/*
137
* Open brace: don't treat specially unless the element is
138
* in braces. In this case, keep a nesting count.
139
*/
140
141
case '{':
142
if (openBraces != 0) {
143
openBraces++;
144
}
145
break;
146
147
/*
148
* Close brace: if element is in braces, keep nesting
149
* count and quit when the last close brace is seen.
150
*/
151
152
case '}':
153
if (openBraces == 1) {
154
char *p2;
155
156
size = p - list;
157
p++;
158
if (isspace(UCHAR(*p)) || (*p == 0)) {
159
goto done;
160
}
161
for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
162
&& (p2 < p+20); p2++) {
163
/* null body */
164
}
165
if (interp != NULL) {
166
Tcl_ResetResult(interp);
167
sprintf(interp->result,
168
"list element in braces followed by \"%.*s\" instead of space",
169
(int) (p2-p), p);
170
}
171
return TCL_ERROR;
172
} else if (openBraces != 0) {
173
openBraces--;
174
}
175
break;
176
177
/*
178
* Backslash: skip over everything up to the end of the
179
* backslash sequence.
180
*/
181
182
case '\\': {
183
int size;
184
185
(void) Tcl_Backslash(p, &size);
186
p += size - 1;
187
break;
188
}
189
190
/*
191
* Space: ignore if element is in braces or quotes; otherwise
192
* terminate element.
193
*/
194
195
case ' ':
196
case '\f':
197
case '\n':
198
case '\r':
199
case '\t':
200
case '\v':
201
if ((openBraces == 0) && !inQuotes) {
202
size = p - list;
203
goto done;
204
}
205
break;
206
207
/*
208
* Double-quote: if element is in quotes then terminate it.
209
*/
210
211
case '"':
212
if (inQuotes) {
213
char *p2;
214
215
size = p-list;
216
p++;
217
if (isspace(UCHAR(*p)) || (*p == 0)) {
218
goto done;
219
}
220
for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
221
&& (p2 < p+20); p2++) {
222
/* null body */
223
}
224
if (interp != NULL) {
225
Tcl_ResetResult(interp);
226
sprintf(interp->result,
227
"list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p,
228
"instead of space");
229
}
230
return TCL_ERROR;
231
}
232
break;
233
234
/*
235
* End of list: terminate element.
236
*/
237
238
case 0:
239
if (openBraces != 0) {
240
if (interp != NULL) {
241
Tcl_SetResult(interp, "unmatched open brace in list",
242
TCL_STATIC);
243
}
244
return TCL_ERROR;
245
} else if (inQuotes) {
246
if (interp != NULL) {
247
Tcl_SetResult(interp, "unmatched open quote in list",
248
TCL_STATIC);
249
}
250
return TCL_ERROR;
251
}
252
size = p - list;
253
goto done;
254
255
}
256
p++;
257
}
258
259
done:
260
while (isspace(UCHAR(*p))) {
261
p++;
262
}
263
*elementPtr = list;
264
*nextPtr = p;
265
if (sizePtr != 0) {
266
*sizePtr = size;
267
}
268
return TCL_OK;
269
}
270
271
/*
272
*----------------------------------------------------------------------
273
*
274
* TclCopyAndCollapse --
275
*
276
* Copy a string and eliminate any backslashes that aren't in braces.
277
*
278
* Results:
279
* There is no return value. Count chars. get copied from src
280
* to dst. Along the way, if backslash sequences are found outside
281
* braces, the backslashes are eliminated in the copy.
282
* After scanning count chars. from source, a null character is
283
* placed at the end of dst.
284
*
285
* Side effects:
286
* None.
287
*
288
*----------------------------------------------------------------------
289
*/
290
291
void
292
TclCopyAndCollapse(count, src, dst)
293
int count; /* Total number of characters to copy
294
* from src. */
295
register char *src; /* Copy from here... */
296
register char *dst; /* ... to here. */
297
{
298
register char c;
299
int numRead;
300
301
for (c = *src; count > 0; src++, c = *src, count--) {
302
if (c == '\\') {
303
*dst = Tcl_Backslash(src, &numRead);
304
dst++;
305
src += numRead-1;
306
count -= numRead-1;
307
} else {
308
*dst = c;
309
dst++;
310
}
311
}
312
*dst = 0;
313
}
314
315
/*
316
*----------------------------------------------------------------------
317
*
318
* Tcl_SplitList --
319
*
320
* Splits a list up into its constituent fields.
321
*
322
* Results
323
* The return value is normally TCL_OK, which means that
324
* the list was successfully split up. If TCL_ERROR is
325
* returned, it means that "list" didn't have proper list
326
* structure; interp->result will contain a more detailed
327
* error message.
328
*
329
* *argvPtr will be filled in with the address of an array
330
* whose elements point to the elements of list, in order.
331
* *argcPtr will get filled in with the number of valid elements
332
* in the array. A single block of memory is dynamically allocated
333
* to hold both the argv array and a copy of the list (with
334
* backslashes and braces removed in the standard way).
335
* The caller must eventually free this memory by calling free()
336
* on *argvPtr. Note: *argvPtr and *argcPtr are only modified
337
* if the procedure returns normally.
338
*
339
* Side effects:
340
* Memory is allocated.
341
*
342
*----------------------------------------------------------------------
343
*/
344
345
int
346
Tcl_TclSplitList(interp, list, argcPtr, argvPtr)
347
Tcl_Interp *interp; /* Interpreter to use for error reporting.
348
* If NULL, then no error message is left. */
349
char *list; /* Pointer to string with list structure. */
350
int *argcPtr; /* Pointer to location to fill in with
351
* the number of elements in the list. */
352
char ***argvPtr; /* Pointer to place to store pointer to array
353
* of pointers to list elements. */
354
{
355
char **argv;
356
register char *p;
357
int size, i, result, elSize, brace;
358
char *element;
359
360
/*
361
* Figure out how much space to allocate. There must be enough
362
* space for both the array of pointers and also for a copy of
363
* the list. To estimate the number of pointers needed, count
364
* the number of space characters in the list.
365
*/
366
367
for (size = 1, p = list; *p != 0; p++) {
368
if (isspace(UCHAR(*p))) {
369
size++;
370
}
371
}
372
size++; /* Leave space for final NULL pointer. */
373
argv = (char **) ckalloc((unsigned)
374
((size * sizeof(char *)) + (p - list) + 1));
375
for (i = 0, p = ((char *) argv) + size*sizeof(char *);
376
*list != 0; i++) {
377
result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
378
if (result != TCL_OK) {
379
ckfree((char *) argv);
380
return result;
381
}
382
if (*element == 0) {
383
break;
384
}
385
if (i >= size) {
386
ckfree((char *) argv);
387
if (interp != NULL) {
388
Tcl_SetResult(interp, "internal error in Tcl_SplitList",
389
TCL_STATIC);
390
}
391
return TCL_ERROR;
392
}
393
argv[i] = p;
394
if (brace) {
395
strncpy(p, element, (size_t) elSize);
396
p += elSize;
397
*p = 0;
398
p++;
399
} else {
400
TclCopyAndCollapse(elSize, element, p);
401
p += elSize+1;
402
}
403
}
404
405
argv[i] = NULL;
406
*argvPtr = argv;
407
*argcPtr = i;
408
return TCL_OK;
409
}
410
411
/*
412
*----------------------------------------------------------------------
413
*
414
* Tcl_ScanElement --
415
*
416
* This procedure is a companion procedure to Tcl_ConvertElement.
417
* It scans a string to see what needs to be done to it (e.g.
418
* add backslashes or enclosing braces) to make the string into
419
* a valid Tcl list element.
420
*
421
* Results:
422
* The return value is an overestimate of the number of characters
423
* that will be needed by Tcl_ConvertElement to produce a valid
424
* list element from string. The word at *flagPtr is filled in
425
* with a value needed by Tcl_ConvertElement when doing the actual
426
* conversion.
427
*
428
* Side effects:
429
* None.
430
*
431
*----------------------------------------------------------------------
432
*/
433
434
int
435
Tcl_TclScanElement(string, flagPtr)
436
char *string; /* String to convert to Tcl list element. */
437
int *flagPtr; /* Where to store information to guide
438
* Tcl_ConvertElement. */
439
{
440
int flags, nestingLevel;
441
register char *p;
442
443
/*
444
* This procedure and Tcl_ConvertElement together do two things:
445
*
446
* 1. They produce a proper list, one that will yield back the
447
* argument strings when evaluated or when disassembled with
448
* Tcl_SplitList. This is the most important thing.
449
*
450
* 2. They try to produce legible output, which means minimizing the
451
* use of backslashes (using braces instead). However, there are
452
* some situations where backslashes must be used (e.g. an element
453
* like "{abc": the leading brace will have to be backslashed. For
454
* each element, one of three things must be done:
455
*
456
* (a) Use the element as-is (it doesn't contain anything special
457
* characters). This is the most desirable option.
458
*
459
* (b) Enclose the element in braces, but leave the contents alone.
460
* This happens if the element contains embedded space, or if it
461
* contains characters with special interpretation ($, [, ;, or \),
462
* or if it starts with a brace or double-quote, or if there are
463
* no characters in the element.
464
*
465
* (c) Don't enclose the element in braces, but add backslashes to
466
* prevent special interpretation of special characters. This is a
467
* last resort used when the argument would normally fall under case
468
* (b) but contains unmatched braces. It also occurs if the last
469
* character of the argument is a backslash or if the element contains
470
* a backslash followed by newline.
471
*
472
* The procedure figures out how many bytes will be needed to store
473
* the result (actually, it overestimates). It also collects information
474
* about the element in the form of a flags word.
475
*/
476
477
nestingLevel = 0;
478
flags = 0;
479
if (string == NULL) {
480
string = "";
481
}
482
p = string;
483
if ((*p == '{') || (*p == '"') || (*p == 0)) {
484
flags |= USE_BRACES;
485
}
486
for ( ; *p != 0; p++) {
487
switch (*p) {
488
case '{':
489
nestingLevel++;
490
break;
491
case '}':
492
nestingLevel--;
493
if (nestingLevel < 0) {
494
flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
495
}
496
break;
497
case '[':
498
case '$':
499
case ';':
500
case ' ':
501
case '\f':
502
case '\n':
503
case '\r':
504
case '\t':
505
case '\v':
506
flags |= USE_BRACES;
507
break;
508
case '\\':
509
if ((p[1] == 0) || (p[1] == '\n')) {
510
flags = TCL_DONT_USE_BRACES;
511
} else {
512
int size;
513
514
(void) Tcl_Backslash(p, &size);
515
p += size-1;
516
flags |= USE_BRACES;
517
}
518
break;
519
}
520
}
521
if (nestingLevel != 0) {
522
flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
523
}
524
*flagPtr = flags;
525
526
/*
527
* Allow enough space to backslash every character plus leave
528
* two spaces for braces.
529
*/
530
531
return 2*(p-string) + 2;
532
}
533
534
/*
535
*----------------------------------------------------------------------
536
*
537
* Tcl_ConvertElement --
538
*
539
* This is a companion procedure to Tcl_ScanElement. Given the
540
* information produced by Tcl_ScanElement, this procedure converts
541
* a string to a list element equal to that string.
542
*
543
* Results:
544
* Information is copied to *dst in the form of a list element
545
* identical to src (i.e. if Tcl_SplitList is applied to dst it
546
* will produce a string identical to src). The return value is
547
* a count of the number of characters copied (not including the
548
* terminating NULL character).
549
*
550
* Side effects:
551
* None.
552
*
553
*----------------------------------------------------------------------
554
*/
555
556
int
557
Tcl_TclConvertElement(src, dst, flags)
558
register char *src; /* Source information for list element. */
559
char *dst; /* Place to put list-ified element. */
560
int flags; /* Flags produced by Tcl_ScanElement. */
561
{
562
register char *p = dst;
563
564
/*
565
* See the comment block at the beginning of the Tcl_ScanElement
566
* code for details of how this works.
567
*/
568
569
if ((src == NULL) || (*src == 0)) {
570
p[0] = '{';
571
p[1] = '}';
572
p[2] = 0;
573
return 2;
574
}
575
if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
576
*p = '{';
577
p++;
578
for ( ; *src != 0; src++, p++) {
579
*p = *src;
580
}
581
*p = '}';
582
p++;
583
} else {
584
if (*src == '{') {
585
/*
586
* Can't have a leading brace unless the whole element is
587
* enclosed in braces. Add a backslash before the brace.
588
* Furthermore, this may destroy the balance between open
589
* and close braces, so set BRACES_UNMATCHED.
590
*/
591
592
p[0] = '\\';
593
p[1] = '{';
594
p += 2;
595
src++;
596
flags |= BRACES_UNMATCHED;
597
}
598
for (; *src != 0 ; src++) {
599
switch (*src) {
600
case ']':
601
case '[':
602
case '$':
603
case ';':
604
case ' ':
605
case '\\':
606
case '"':
607
*p = '\\';
608
p++;
609
break;
610
case '{':
611
case '}':
612
/*
613
* It may not seem necessary to backslash braces, but
614
* it is. The reason for this is that the resulting
615
* list element may actually be an element of a sub-list
616
* enclosed in braces (e.g. if Tcl_DStringStartSublist
617
* has been invoked), so there may be a brace mismatch
618
* if the braces aren't backslashed.
619
*/
620
621
if (flags & BRACES_UNMATCHED) {
622
*p = '\\';
623
p++;
624
}
625
break;
626
case '\f':
627
*p = '\\';
628
p++;
629
*p = 'f';
630
p++;
631
continue;
632
case '\n':
633
*p = '\\';
634
p++;
635
*p = 'n';
636
p++;
637
continue;
638
case '\r':
639
*p = '\\';
640
p++;
641
*p = 'r';
642
p++;
643
continue;
644
case '\t':
645
*p = '\\';
646
p++;
647
*p = 't';
648
p++;
649
continue;
650
case '\v':
651
*p = '\\';
652
p++;
653
*p = 'v';
654
p++;
655
continue;
656
}
657
*p = *src;
658
p++;
659
}
660
}
661
*p = '\0';
662
return p-dst;
663
}
664
665
/*
666
*----------------------------------------------------------------------
667
*
668
* Tcl_Merge --
669
*
670
* Given a collection of strings, merge them together into a
671
* single string that has proper Tcl list structured (i.e.
672
* Tcl_SplitList may be used to retrieve strings equal to the
673
* original elements, and Tcl_Eval will parse the string back
674
* into its original elements).
675
*
676
* Results:
677
* The return value is the address of a dynamically-allocated
678
* string containing the merged list.
679
*
680
* Side effects:
681
* None.
682
*
683
*----------------------------------------------------------------------
684
*/
685
686
char *
687
Tcl_TclMerge(argc, argv)
688
int argc; /* How many strings to merge. */
689
char **argv; /* Array of string values. */
690
{
691
# define LOCAL_SIZE 20
692
int localFlags[LOCAL_SIZE], *flagPtr;
693
int numChars;
694
char *result;
695
register char *dst;
696
int i;
697
698
/*
699
* Pass 1: estimate space, gather flags.
700
*/
701
702
if (argc <= LOCAL_SIZE) {
703
flagPtr = localFlags;
704
} else {
705
flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
706
}
707
numChars = 1;
708
for (i = 0; i < argc; i++) {
709
numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
710
}
711
712
/*
713
* Pass two: copy into the result area.
714
*/
715
716
result = (char *) ckalloc((unsigned) numChars);
717
dst = result;
718
for (i = 0; i < argc; i++) {
719
numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
720
dst += numChars;
721
*dst = ' ';
722
dst++;
723
}
724
if (dst == result) {
725
*dst = 0;
726
} else {
727
dst[-1] = 0;
728
}
729
730
if (flagPtr != localFlags) {
731
ckfree((char *) flagPtr);
732
}
733
return result;
734
}
735
736
/*
737
*----------------------------------------------------------------------
738
*
739
* Tcl_Concat --
740
*
741
* Concatenate a set of strings into a single large string.
742
*
743
* Results:
744
* The return value is dynamically-allocated string containing
745
* a concatenation of all the strings in argv, with spaces between
746
* the original argv elements.
747
*
748
* Side effects:
749
* Memory is allocated for the result; the caller is responsible
750
* for freeing the memory.
751
*
752
*----------------------------------------------------------------------
753
*/
754
755
char *
756
Tcl_Concat(argc, argv)
757
int argc; /* Number of strings to concatenate. */
758
char **argv; /* Array of strings to concatenate. */
759
{
760
int totalSize, i;
761
register char *p;
762
char *result;
763
764
for (totalSize = 1, i = 0; i < argc; i++) {
765
totalSize += strlen(argv[i]) + 1;
766
}
767
result = (char *) ckalloc((unsigned) totalSize);
768
if (argc == 0) {
769
*result = '\0';
770
return result;
771
}
772
for (p = result, i = 0; i < argc; i++) {
773
char *element;
774
int length;
775
776
/*
777
* Clip white space off the front and back of the string
778
* to generate a neater result, and ignore any empty
779
* elements.
780
*/
781
782
element = argv[i];
783
while (isspace(UCHAR(*element))) {
784
element++;
785
}
786
for (length = strlen(element);
787
(length > 0) && (isspace(UCHAR(element[length-1])));
788
length--) {
789
/* Null loop body. */
790
}
791
if (length == 0) {
792
continue;
793
}
794
(void) strncpy(p, element, (size_t) length);
795
p += length;
796
*p = ' ';
797
p++;
798
}
799
if (p != result) {
800
p[-1] = 0;
801
} else {
802
*p = 0;
803
}
804
return result;
805
}
806
807
/*
808
*----------------------------------------------------------------------
809
*
810
* Tcl_StringMatch --
811
*
812
* See if a particular string matches a particular pattern.
813
*
814
* Results:
815
* The return value is 1 if string matches pattern, and
816
* 0 otherwise. The matching operation permits the following
817
* special characters in the pattern: *?\[] (see the manual
818
* entry for details on what these mean).
819
*
820
* Side effects:
821
* None.
822
*
823
*----------------------------------------------------------------------
824
*/
825
826
int
827
Tcl_StringMatch(string, pattern)
828
register char *string; /* String. */
829
register char *pattern; /* Pattern, which may contain
830
* special characters. */
831
{
832
char c2;
833
834
while (1) {
835
/* See if we're at the end of both the pattern and the string.
836
* If so, we succeeded. If we're at the end of the pattern
837
* but not at the end of the string, we failed.
838
*/
839
840
if (*pattern == 0) {
841
if (*string == 0) {
842
return 1;
843
} else {
844
return 0;
845
}
846
}
847
if ((*string == 0) && (*pattern != '*')) {
848
return 0;
849
}
850
851
/* Check for a "*" as the next pattern character. It matches
852
* any substring. We handle this by calling ourselves
853
* recursively for each postfix of string, until either we
854
* match or we reach the end of the string.
855
*/
856
857
if (*pattern == '*') {
858
pattern += 1;
859
if (*pattern == 0) {
860
return 1;
861
}
862
while (1) {
863
if (Tcl_StringMatch(string, pattern)) {
864
return 1;
865
}
866
if (*string == 0) {
867
return 0;
868
}
869
string += 1;
870
}
871
}
872
873
/* Check for a "?" as the next pattern character. It matches
874
* any single character.
875
*/
876
877
if (*pattern == '?') {
878
goto thisCharOK;
879
}
880
881
/* Check for a "[" as the next pattern character. It is followed
882
* by a list of characters that are acceptable, or by a range
883
* (two characters separated by "-").
884
*/
885
886
if (*pattern == '[') {
887
pattern += 1;
888
while (1) {
889
if ((*pattern == ']') || (*pattern == 0)) {
890
return 0;
891
}
892
if (*pattern == *string) {
893
break;
894
}
895
if (pattern[1] == '-') {
896
c2 = pattern[2];
897
if (c2 == 0) {
898
return 0;
899
}
900
if ((*pattern <= *string) && (c2 >= *string)) {
901
break;
902
}
903
if ((*pattern >= *string) && (c2 <= *string)) {
904
break;
905
}
906
pattern += 2;
907
}
908
pattern += 1;
909
}
910
while (*pattern != ']') {
911
if (*pattern == 0) {
912
pattern--;
913
break;
914
}
915
pattern += 1;
916
}
917
goto thisCharOK;
918
}
919
920
/* If the next pattern character is '/', just strip off the '/'
921
* so we do exact matching on the character that follows.
922
*/
923
924
if (*pattern == '\\') {
925
pattern += 1;
926
if (*pattern == 0) {
927
return 0;
928
}
929
}
930
931
/* There's no special character. Just make sure that the next
932
* characters of each string match.
933
*/
934
935
if (*pattern != *string) {
936
return 0;
937
}
938
939
thisCharOK: pattern += 1;
940
string += 1;
941
}
942
}
943
944
/*
945
*----------------------------------------------------------------------
946
*
947
* Tcl_SetResult --
948
*
949
* Arrange for "string" to be the Tcl return value.
950
*
951
* Results:
952
* None.
953
*
954
* Side effects:
955
* interp->result is left pointing either to "string" (if "copy" is 0)
956
* or to a copy of string.
957
*
958
*----------------------------------------------------------------------
959
*/
960
961
void
962
Tcl_SetResult(interp, string, freeProc)
963
Tcl_Interp *interp; /* Interpreter with which to associate the
964
* return value. */
965
char *string; /* Value to be returned. If NULL,
966
* the result is set to an empty string. */
967
Tcl_FreeProc *freeProc; /* Gives information about the string:
968
* TCL_STATIC, TCL_VOLATILE, or the address
969
* of a Tcl_FreeProc such as free. */
970
{
971
register Interp *iPtr = (Interp *) interp;
972
int length;
973
Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
974
char *oldResult = iPtr->result;
975
976
if (string == NULL) {
977
iPtr->resultSpace[0] = 0;
978
iPtr->result = iPtr->resultSpace;
979
iPtr->freeProc = 0;
980
} else if (freeProc == TCL_VOLATILE) {
981
length = strlen(string);
982
if (length > TCL_RESULT_SIZE) {
983
iPtr->result = (char *) ckalloc((unsigned) length+1);
984
iPtr->freeProc = TCL_DYNAMIC;
985
} else {
986
iPtr->result = iPtr->resultSpace;
987
iPtr->freeProc = 0;
988
}
989
strcpy(iPtr->result, string);
990
} else {
991
iPtr->result = string;
992
iPtr->freeProc = freeProc;
993
}
994
995
/*
996
* If the old result was dynamically-allocated, free it up. Do it
997
* here, rather than at the beginning, in case the new result value
998
* was part of the old result value.
999
*/
1000
1001
if (oldFreeProc != 0) {
1002
if ((oldFreeProc == TCL_DYNAMIC)
1003
|| (oldFreeProc == (Tcl_FreeProc *) free)) {
1004
ckfree(oldResult);
1005
} else {
1006
(*oldFreeProc)(oldResult);
1007
}
1008
}
1009
}
1010
1011
/*
1012
*----------------------------------------------------------------------
1013
*
1014
* Tcl_AppendResult --
1015
*
1016
* Append a variable number of strings onto the result already
1017
* present for an interpreter.
1018
*
1019
* Results:
1020
* None.
1021
*
1022
* Side effects:
1023
* The result in the interpreter given by the first argument
1024
* is extended by the strings given by the second and following
1025
* arguments (up to a terminating NULL argument).
1026
*
1027
*----------------------------------------------------------------------
1028
*/
1029
1030
/* VARARGS2 */
1031
void
1032
Tcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1)
1033
{
1034
va_list argList;
1035
register Interp *iPtr;
1036
char *string;
1037
int newSpace;
1038
1039
/*
1040
* First, scan through all the arguments to see how much space is
1041
* needed.
1042
*/
1043
1044
iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
1045
newSpace = 0;
1046
while (1) {
1047
string = va_arg(argList, char *);
1048
if (string == NULL) {
1049
break;
1050
}
1051
newSpace += strlen(string);
1052
}
1053
va_end(argList);
1054
1055
/*
1056
* If the append buffer isn't already setup and large enough
1057
* to hold the new data, set it up.
1058
*/
1059
1060
if ((iPtr->result != iPtr->appendResult)
1061
|| (iPtr->appendResult[iPtr->appendUsed] != 0)
1062
|| ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
1063
SetupAppendBuffer(iPtr, newSpace);
1064
}
1065
1066
/*
1067
* Final step: go through all the argument strings again, copying
1068
* them into the buffer.
1069
*/
1070
1071
TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
1072
while (1) {
1073
string = va_arg(argList, char *);
1074
if (string == NULL) {
1075
break;
1076
}
1077
strcpy(iPtr->appendResult + iPtr->appendUsed, string);
1078
iPtr->appendUsed += strlen(string);
1079
}
1080
va_end(argList);
1081
}
1082
1083
/*
1084
*----------------------------------------------------------------------
1085
*
1086
* Tcl_AppendElement --
1087
*
1088
* Convert a string to a valid Tcl list element and append it
1089
* to the current result (which is ostensibly a list).
1090
*
1091
* Results:
1092
* None.
1093
*
1094
* Side effects:
1095
* The result in the interpreter given by the first argument
1096
* is extended with a list element converted from string. A
1097
* separator space is added before the converted list element
1098
* unless the current result is empty, contains the single
1099
* character "{", or ends in " {".
1100
*
1101
*----------------------------------------------------------------------
1102
*/
1103
1104
void
1105
Tcl_AppendElement(interp, string)
1106
Tcl_Interp *interp; /* Interpreter whose result is to be
1107
* extended. */
1108
char *string; /* String to convert to list element and
1109
* add to result. */
1110
{
1111
register Interp *iPtr = (Interp *) interp;
1112
int size, flags;
1113
char *dst;
1114
1115
/*
1116
* See how much space is needed, and grow the append buffer if
1117
* needed to accommodate the list element.
1118
*/
1119
1120
size = Tcl_ScanElement(string, &flags) + 1;
1121
if ((iPtr->result != iPtr->appendResult)
1122
|| (iPtr->appendResult[iPtr->appendUsed] != 0)
1123
|| ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
1124
SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
1125
}
1126
1127
/*
1128
* Convert the string into a list element and copy it to the
1129
* buffer that's forming, with a space separator if needed.
1130
*/
1131
1132
dst = iPtr->appendResult + iPtr->appendUsed;
1133
if (TclNeedSpace(iPtr->appendResult, dst)) {
1134
iPtr->appendUsed++;
1135
*dst = ' ';
1136
dst++;
1137
}
1138
iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
1139
}
1140
1141
/*
1142
*----------------------------------------------------------------------
1143
*
1144
* SetupAppendBuffer --
1145
*
1146
* This procedure makes sure that there is an append buffer
1147
* properly initialized for interp, and that it has at least
1148
* enough room to accommodate newSpace new bytes of information.
1149
*
1150
* Results:
1151
* None.
1152
*
1153
* Side effects:
1154
* None.
1155
*
1156
*----------------------------------------------------------------------
1157
*/
1158
1159
static void
1160
SetupAppendBuffer(iPtr, newSpace)
1161
register Interp *iPtr; /* Interpreter whose result is being set up. */
1162
int newSpace; /* Make sure that at least this many bytes
1163
* of new information may be added. */
1164
{
1165
int totalSpace;
1166
1167
/*
1168
* Make the append buffer larger, if that's necessary, then
1169
* copy the current result into the append buffer and make the
1170
* append buffer the official Tcl result.
1171
*/
1172
1173
if (iPtr->result != iPtr->appendResult) {
1174
/*
1175
* If an oversized buffer was used recently, then free it up
1176
* so we go back to a smaller buffer. This avoids tying up
1177
* memory forever after a large operation.
1178
*/
1179
1180
if (iPtr->appendAvl > 500) {
1181
ckfree(iPtr->appendResult);
1182
iPtr->appendResult = NULL;
1183
iPtr->appendAvl = 0;
1184
}
1185
iPtr->appendUsed = strlen(iPtr->result);
1186
} else if (iPtr->result[iPtr->appendUsed] != 0) {
1187
/*
1188
* Most likely someone has modified a result created by
1189
* Tcl_AppendResult et al. so that it has a different size.
1190
* Just recompute the size.
1191
*/
1192
1193
iPtr->appendUsed = strlen(iPtr->result);
1194
}
1195
totalSpace = newSpace + iPtr->appendUsed;
1196
if (totalSpace >= iPtr->appendAvl) {
1197
char *new;
1198
1199
if (totalSpace < 100) {
1200
totalSpace = 200;
1201
} else {
1202
totalSpace *= 2;
1203
}
1204
new = (char *) ckalloc((unsigned) totalSpace);
1205
strcpy(new, iPtr->result);
1206
if (iPtr->appendResult != NULL) {
1207
ckfree(iPtr->appendResult);
1208
}
1209
iPtr->appendResult = new;
1210
iPtr->appendAvl = totalSpace;
1211
} else if (iPtr->result != iPtr->appendResult) {
1212
strcpy(iPtr->appendResult, iPtr->result);
1213
}
1214
Tcl_FreeResult(iPtr);
1215
iPtr->result = iPtr->appendResult;
1216
}
1217
1218
/*
1219
*----------------------------------------------------------------------
1220
*
1221
* Tcl_ResetResult --
1222
*
1223
* This procedure restores the result area for an interpreter
1224
* to its default initialized state, freeing up any memory that
1225
* may have been allocated for the result and clearing any
1226
* error information for the interpreter.
1227
*
1228
* Results:
1229
* None.
1230
*
1231
* Side effects:
1232
* None.
1233
*
1234
*----------------------------------------------------------------------
1235
*/
1236
1237
void
1238
Tcl_ResetResult(interp)
1239
Tcl_Interp *interp; /* Interpreter for which to clear result. */
1240
{
1241
register Interp *iPtr = (Interp *) interp;
1242
1243
Tcl_FreeResult(iPtr);
1244
iPtr->result = iPtr->resultSpace;
1245
iPtr->resultSpace[0] = 0;
1246
iPtr->flags &=
1247
~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
1248
}
1249
1250
/*
1251
*----------------------------------------------------------------------
1252
*
1253
* Tcl_SetErrorCode --
1254
*
1255
* This procedure is called to record machine-readable information
1256
* about an error that is about to be returned.
1257
*
1258
* Results:
1259
* None.
1260
*
1261
* Side effects:
1262
* The errorCode global variable is modified to hold all of the
1263
* arguments to this procedure, in a list form with each argument
1264
* becoming one element of the list. A flag is set internally
1265
* to remember that errorCode has been set, so the variable doesn't
1266
* get set automatically when the error is returned.
1267
*
1268
*----------------------------------------------------------------------
1269
*/
1270
/* VARARGS2 */
1271
void
1272
Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1)
1273
{
1274
va_list argList;
1275
char *string;
1276
int flags;
1277
Interp *iPtr;
1278
1279
/*
1280
* Scan through the arguments one at a time, appending them to
1281
* $errorCode as list elements.
1282
*/
1283
1284
iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
1285
flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
1286
while (1) {
1287
string = va_arg(argList, char *);
1288
if (string == NULL) {
1289
break;
1290
}
1291
(void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
1292
(char *) NULL, string, flags);
1293
flags |= TCL_APPEND_VALUE;
1294
}
1295
va_end(argList);
1296
iPtr->flags |= ERROR_CODE_SET;
1297
}
1298
1299
/*
1300
*----------------------------------------------------------------------
1301
*
1302
* TclGetListIndex --
1303
*
1304
* Parse a list index, which may be either an integer or the
1305
* value "end".
1306
*
1307
* Results:
1308
* The return value is either TCL_OK or TCL_ERROR. If it is
1309
* TCL_OK, then the index corresponding to string is left in
1310
* *indexPtr. If the return value is TCL_ERROR, then string
1311
* was bogus; an error message is returned in interp->result.
1312
* If a negative index is specified, it is rounded up to 0.
1313
* The index value may be larger than the size of the list
1314
* (this happens when "end" is specified).
1315
*
1316
* Side effects:
1317
* None.
1318
*
1319
*----------------------------------------------------------------------
1320
*/
1321
1322
int
1323
TclGetListIndex(interp, string, indexPtr)
1324
Tcl_Interp *interp; /* Interpreter for error reporting. */
1325
char *string; /* String containing list index. */
1326
int *indexPtr; /* Where to store index. */
1327
{
1328
if (isdigit(UCHAR(*string)) || (*string == '-')) {
1329
if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
1330
return TCL_ERROR;
1331
}
1332
if (*indexPtr < 0) {
1333
*indexPtr = 0;
1334
}
1335
} else if (strncmp(string, "end", strlen(string)) == 0) {
1336
*indexPtr = INT_MAX;
1337
} else {
1338
Tcl_AppendResult(interp, "bad index \"", string,
1339
"\": must be integer or \"end\"", (char *) NULL);
1340
return TCL_ERROR;
1341
}
1342
return TCL_OK;
1343
}
1344
1345
/*
1346
*----------------------------------------------------------------------
1347
*
1348
* Tcl_RegExpCompile --
1349
*
1350
* Compile a regular expression into a form suitable for fast
1351
* matching. This procedure retains a small cache of pre-compiled
1352
* regular expressions in the interpreter, in order to avoid
1353
* compilation costs as much as possible.
1354
*
1355
* Results:
1356
* The return value is a pointer to the compiled form of string,
1357
* suitable for passing to Tcl_RegExpExec. This compiled form
1358
* is only valid up until the next call to this procedure, so
1359
* don't keep these around for a long time! If an error occurred
1360
* while compiling the pattern, then NULL is returned and an error
1361
* message is left in interp->result.
1362
*
1363
* Side effects:
1364
* The cache of compiled regexp's in interp will be modified to
1365
* hold information for string, if such information isn't already
1366
* present in the cache.
1367
*
1368
*----------------------------------------------------------------------
1369
*/
1370
1371
Tcl_RegExp
1372
Tcl_RegExpCompile(interp, string)
1373
Tcl_Interp *interp; /* For use in error reporting. */
1374
char *string; /* String for which to produce
1375
* compiled regular expression. */
1376
{
1377
register Interp *iPtr = (Interp *) interp;
1378
int i, length;
1379
regexp *result;
1380
1381
length = strlen(string);
1382
for (i = 0; i < NUM_REGEXPS; i++) {
1383
if ((length == iPtr->patLengths[i])
1384
&& (strcmp(string, iPtr->patterns[i]) == 0)) {
1385
/*
1386
* Move the matched pattern to the first slot in the
1387
* cache and shift the other patterns down one position.
1388
*/
1389
1390
if (i != 0) {
1391
int j;
1392
char *cachedString;
1393
1394
cachedString = iPtr->patterns[i];
1395
result = iPtr->regexps[i];
1396
for (j = i-1; j >= 0; j--) {
1397
iPtr->patterns[j+1] = iPtr->patterns[j];
1398
iPtr->patLengths[j+1] = iPtr->patLengths[j];
1399
iPtr->regexps[j+1] = iPtr->regexps[j];
1400
}
1401
iPtr->patterns[0] = cachedString;
1402
iPtr->patLengths[0] = length;
1403
iPtr->regexps[0] = result;
1404
}
1405
return (Tcl_RegExp) iPtr->regexps[0];
1406
}
1407
}
1408
1409
/*
1410
* No match in the cache. Compile the string and add it to the
1411
* cache.
1412
*/
1413
1414
TclRegError((char *) NULL);
1415
result = TclRegComp(string);
1416
if (TclGetRegError() != NULL) {
1417
Tcl_AppendResult(interp,
1418
"couldn't compile regular expression pattern: ",
1419
TclGetRegError(), (char *) NULL);
1420
return NULL;
1421
}
1422
if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
1423
ckfree(iPtr->patterns[NUM_REGEXPS-1]);
1424
ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
1425
}
1426
for (i = NUM_REGEXPS - 2; i >= 0; i--) {
1427
iPtr->patterns[i+1] = iPtr->patterns[i];
1428
iPtr->patLengths[i+1] = iPtr->patLengths[i];
1429
iPtr->regexps[i+1] = iPtr->regexps[i];
1430
}
1431
iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
1432
strcpy(iPtr->patterns[0], string);
1433
iPtr->patLengths[0] = length;
1434
iPtr->regexps[0] = result;
1435
return (Tcl_RegExp) result;
1436
}
1437
1438
/*
1439
*----------------------------------------------------------------------
1440
*
1441
* Tcl_RegExpExec --
1442
*
1443
* Execute the regular expression matcher using a compiled form
1444
* of a regular expression and save information about any match
1445
* that is found.
1446
*
1447
* Results:
1448
* If an error occurs during the matching operation then -1
1449
* is returned and interp->result contains an error message.
1450
* Otherwise the return value is 1 if a matching range is
1451
* found and 0 if there is no matching range.
1452
*
1453
* Side effects:
1454
* None.
1455
*
1456
*----------------------------------------------------------------------
1457
*/
1458
1459
int
1460
Tcl_RegExpExec(interp, re, string, start)
1461
Tcl_Interp *interp; /* Interpreter to use for error reporting. */
1462
Tcl_RegExp re; /* Compiled regular expression; must have
1463
* been returned by previous call to
1464
* Tcl_RegExpCompile. */
1465
char *string; /* String against which to match re. */
1466
char *start; /* If string is part of a larger string,
1467
* this identifies beginning of larger
1468
* string, so that "^" won't match. */
1469
{
1470
int match;
1471
1472
regexp *regexpPtr = (regexp *) re;
1473
TclRegError((char *) NULL);
1474
match = TclRegExec(regexpPtr, string, start);
1475
if (TclGetRegError() != NULL) {
1476
Tcl_ResetResult(interp);
1477
Tcl_AppendResult(interp, "error while matching regular expression: ",
1478
TclGetRegError(), (char *) NULL);
1479
return -1;
1480
}
1481
return match;
1482
}
1483
1484
/*
1485
*----------------------------------------------------------------------
1486
*
1487
* Tcl_RegExpRange --
1488
*
1489
* Returns pointers describing the range of a regular expression match,
1490
* or one of the subranges within the match.
1491
*
1492
* Results:
1493
* The variables at *startPtr and *endPtr are modified to hold the
1494
* addresses of the endpoints of the range given by index. If the
1495
* specified range doesn't exist then NULLs are returned.
1496
*
1497
* Side effects:
1498
* None.
1499
*
1500
*----------------------------------------------------------------------
1501
*/
1502
1503
void
1504
Tcl_RegExpRange(re, index, startPtr, endPtr)
1505
Tcl_RegExp re; /* Compiled regular expression that has
1506
* been passed to Tcl_RegExpExec. */
1507
int index; /* 0 means give the range of the entire
1508
* match, > 0 means give the range of
1509
* a matching subrange. Must be no greater
1510
* than NSUBEXP. */
1511
char **startPtr; /* Store address of first character in
1512
* (sub-) range here. */
1513
char **endPtr; /* Store address of character just after last
1514
* in (sub-) range here. */
1515
{
1516
regexp *regexpPtr = (regexp *) re;
1517
1518
if (index >= NSUBEXP) {
1519
*startPtr = *endPtr = NULL;
1520
} else {
1521
*startPtr = regexpPtr->startp[index];
1522
*endPtr = regexpPtr->endp[index];
1523
}
1524
}
1525
1526
/*
1527
*----------------------------------------------------------------------
1528
*
1529
* Tcl_RegExpMatch --
1530
*
1531
* See if a string matches a regular expression.
1532
*
1533
* Results:
1534
* If an error occurs during the matching operation then -1
1535
* is returned and interp->result contains an error message.
1536
* Otherwise the return value is 1 if "string" matches "pattern"
1537
* and 0 otherwise.
1538
*
1539
* Side effects:
1540
* None.
1541
*
1542
*----------------------------------------------------------------------
1543
*/
1544
1545
int
1546
Tcl_RegExpMatch(interp, string, pattern)
1547
Tcl_Interp *interp; /* Used for error reporting. */
1548
char *string; /* String. */
1549
char *pattern; /* Regular expression to match against
1550
* string. */
1551
{
1552
Tcl_RegExp re;
1553
1554
re = Tcl_RegExpCompile(interp, pattern);
1555
if (re == NULL) {
1556
return -1;
1557
}
1558
return Tcl_RegExpExec(interp, re, string, string);
1559
}
1560
1561
/*
1562
*----------------------------------------------------------------------
1563
*
1564
* Tcl_DStringInit --
1565
*
1566
* Initializes a dynamic string, discarding any previous contents
1567
* of the string (Tcl_DStringFree should have been called already
1568
* if the dynamic string was previously in use).
1569
*
1570
* Results:
1571
* None.
1572
*
1573
* Side effects:
1574
* The dynamic string is initialized to be empty.
1575
*
1576
*----------------------------------------------------------------------
1577
*/
1578
1579
void
1580
Tcl_DStringInit(dsPtr)
1581
register Tcl_DString *dsPtr; /* Pointer to structure for
1582
* dynamic string. */
1583
{
1584
dsPtr->string = dsPtr->staticSpace;
1585
dsPtr->length = 0;
1586
dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
1587
dsPtr->staticSpace[0] = 0;
1588
}
1589
1590
/*
1591
*----------------------------------------------------------------------
1592
*
1593
* Tcl_DStringAppend --
1594
*
1595
* Append more characters to the current value of a dynamic string.
1596
*
1597
* Results:
1598
* The return value is a pointer to the dynamic string's new value.
1599
*
1600
* Side effects:
1601
* Length bytes from string (or all of string if length is less
1602
* than zero) are added to the current value of the string. Memory
1603
* gets reallocated if needed to accomodate the string's new size.
1604
*
1605
*----------------------------------------------------------------------
1606
*/
1607
1608
char *
1609
Tcl_DStringAppend(dsPtr, string, length)
1610
register Tcl_DString *dsPtr; /* Structure describing dynamic
1611
* string. */
1612
char *string; /* String to append. If length is
1613
* -1 then this must be
1614
* null-terminated. */
1615
int length; /* Number of characters from string
1616
* to append. If < 0, then append all
1617
* of string, up to null at end. */
1618
{
1619
int newSize;
1620
char *newString, *dst, *end;
1621
1622
if (length < 0) {
1623
length = strlen(string);
1624
}
1625
newSize = length + dsPtr->length;
1626
1627
/*
1628
* Allocate a larger buffer for the string if the current one isn't
1629
* large enough. Allocate extra space in the new buffer so that there
1630
* will be room to grow before we have to allocate again.
1631
*/
1632
1633
if (newSize >= dsPtr->spaceAvl) {
1634
dsPtr->spaceAvl = newSize*2;
1635
newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
1636
memcpy((VOID *)newString, (VOID *) dsPtr->string,
1637
(size_t) dsPtr->length);
1638
if (dsPtr->string != dsPtr->staticSpace) {
1639
ckfree(dsPtr->string);
1640
}
1641
dsPtr->string = newString;
1642
}
1643
1644
/*
1645
* Copy the new string into the buffer at the end of the old
1646
* one.
1647
*/
1648
1649
for (dst = dsPtr->string + dsPtr->length, end = string+length;
1650
string < end; string++, dst++) {
1651
*dst = *string;
1652
}
1653
*dst = 0;
1654
dsPtr->length += length;
1655
return dsPtr->string;
1656
}
1657
1658
/*
1659
*----------------------------------------------------------------------
1660
*
1661
* Tcl_DStringAppendElement --
1662
*
1663
* Append a list element to the current value of a dynamic string.
1664
*
1665
* Results:
1666
* The return value is a pointer to the dynamic string's new value.
1667
*
1668
* Side effects:
1669
* String is reformatted as a list element and added to the current
1670
* value of the string. Memory gets reallocated if needed to
1671
* accomodate the string's new size.
1672
*
1673
*----------------------------------------------------------------------
1674
*/
1675
1676
char *
1677
Tcl_DStringAppendElement(dsPtr, string)
1678
register Tcl_DString *dsPtr; /* Structure describing dynamic
1679
* string. */
1680
char *string; /* String to append. Must be
1681
* null-terminated. */
1682
{
1683
int newSize, flags;
1684
char *dst, *newString;
1685
1686
newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
1687
1688
/*
1689
* Allocate a larger buffer for the string if the current one isn't
1690
* large enough. Allocate extra space in the new buffer so that there
1691
* will be room to grow before we have to allocate again.
1692
* SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
1693
* to a larger buffer, since there may be embedded NULLs in the
1694
* string in some cases.
1695
*/
1696
1697
if (newSize >= dsPtr->spaceAvl) {
1698
dsPtr->spaceAvl = newSize*2;
1699
newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
1700
memcpy((VOID *) newString, (VOID *) dsPtr->string,
1701
(size_t) dsPtr->length);
1702
if (dsPtr->string != dsPtr->staticSpace) {
1703
ckfree(dsPtr->string);
1704
}
1705
dsPtr->string = newString;
1706
}
1707
1708
/*
1709
* Convert the new string to a list element and copy it into the
1710
* buffer at the end, with a space, if needed.
1711
*/
1712
1713
dst = dsPtr->string + dsPtr->length;
1714
if (TclNeedSpace(dsPtr->string, dst)) {
1715
*dst = ' ';
1716
dst++;
1717
dsPtr->length++;
1718
}
1719
dsPtr->length += Tcl_ConvertElement(string, dst, flags);
1720
return dsPtr->string;
1721
}
1722
1723
/*
1724
*----------------------------------------------------------------------
1725
*
1726
* Tcl_DStringSetLength --
1727
*
1728
* Change the length of a dynamic string. This can cause the
1729
* string to either grow or shrink, depending on the value of
1730
* length.
1731
*
1732
* Results:
1733
* None.
1734
*
1735
* Side effects:
1736
* The length of dsPtr is changed to length and a null byte is
1737
* stored at that position in the string. If length is larger
1738
* than the space allocated for dsPtr, then a panic occurs.
1739
*
1740
*----------------------------------------------------------------------
1741
*/
1742
1743
void
1744
Tcl_DStringSetLength(dsPtr, length)
1745
register Tcl_DString *dsPtr; /* Structure describing dynamic
1746
* string. */
1747
int length; /* New length for dynamic string. */
1748
{
1749
if (length < 0) {
1750
length = 0;
1751
}
1752
if (length >= dsPtr->spaceAvl) {
1753
char *newString;
1754
1755
dsPtr->spaceAvl = length+1;
1756
newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
1757
1758
/*
1759
* SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
1760
* to a larger buffer, since there may be embedded NULLs in the
1761
* string in some cases.
1762
*/
1763
1764
memcpy((VOID *) newString, (VOID *) dsPtr->string,
1765
(size_t) dsPtr->length);
1766
if (dsPtr->string != dsPtr->staticSpace) {
1767
ckfree(dsPtr->string);
1768
}
1769
dsPtr->string = newString;
1770
}
1771
dsPtr->length = length;
1772
dsPtr->string[length] = 0;
1773
}
1774
1775
/*
1776
*----------------------------------------------------------------------
1777
*
1778
* Tcl_DStringFree --
1779
*
1780
* Frees up any memory allocated for the dynamic string and
1781
* reinitializes the string to an empty state.
1782
*
1783
* Results:
1784
* None.
1785
*
1786
* Side effects:
1787
* The previous contents of the dynamic string are lost, and
1788
* the new value is an empty string.
1789
*
1790
*----------------------------------------------------------------------
1791
*/
1792
1793
void
1794
Tcl_DStringFree(dsPtr)
1795
register Tcl_DString *dsPtr; /* Structure describing dynamic
1796
* string. */
1797
{
1798
if (dsPtr->string != dsPtr->staticSpace) {
1799
ckfree(dsPtr->string);
1800
}
1801
dsPtr->string = dsPtr->staticSpace;
1802
dsPtr->length = 0;
1803
dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
1804
dsPtr->staticSpace[0] = 0;
1805
}
1806
1807
/*
1808
*----------------------------------------------------------------------
1809
*
1810
* Tcl_DStringResult --
1811
*
1812
* This procedure moves the value of a dynamic string into an
1813
* interpreter as its result. The string itself is reinitialized
1814
* to an empty string.
1815
*
1816
* Results:
1817
* None.
1818
*
1819
* Side effects:
1820
* The string is "moved" to interp's result, and any existing
1821
* result for interp is freed up. DsPtr is reinitialized to
1822
* an empty string.
1823
*
1824
*----------------------------------------------------------------------
1825
*/
1826
1827
void
1828
Tcl_DStringResult(interp, dsPtr)
1829
Tcl_Interp *interp; /* Interpreter whose result is to be
1830
* reset. */
1831
Tcl_DString *dsPtr; /* Dynamic string that is to become
1832
* the result of interp. */
1833
{
1834
Tcl_ResetResult(interp);
1835
if (dsPtr->string != dsPtr->staticSpace) {
1836
interp->result = dsPtr->string;
1837
interp->freeProc = TCL_DYNAMIC;
1838
} else if (dsPtr->length < TCL_RESULT_SIZE) {
1839
interp->result = ((Interp *) interp)->resultSpace;
1840
strcpy(interp->result, dsPtr->string);
1841
} else {
1842
Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
1843
}
1844
dsPtr->string = dsPtr->staticSpace;
1845
dsPtr->length = 0;
1846
dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
1847
dsPtr->staticSpace[0] = 0;
1848
}
1849
1850
/*
1851
*----------------------------------------------------------------------
1852
*
1853
* Tcl_DStringGetResult --
1854
*
1855
* This procedure moves the result of an interpreter into a
1856
* dynamic string.
1857
*
1858
* Results:
1859
* None.
1860
*
1861
* Side effects:
1862
* The interpreter's result is cleared, and the previous contents
1863
* of dsPtr are freed.
1864
*
1865
*----------------------------------------------------------------------
1866
*/
1867
1868
void
1869
Tcl_DStringGetResult(interp, dsPtr)
1870
Tcl_Interp *interp; /* Interpreter whose result is to be
1871
* reset. */
1872
Tcl_DString *dsPtr; /* Dynamic string that is to become
1873
* the result of interp. */
1874
{
1875
Interp *iPtr = (Interp *) interp;
1876
if (dsPtr->string != dsPtr->staticSpace) {
1877
ckfree(dsPtr->string);
1878
}
1879
dsPtr->length = strlen(iPtr->result);
1880
if (iPtr->freeProc != NULL) {
1881
if ((iPtr->freeProc == TCL_DYNAMIC)
1882
|| (iPtr->freeProc == (Tcl_FreeProc *) free)) {
1883
dsPtr->string = iPtr->result;
1884
dsPtr->spaceAvl = dsPtr->length+1;
1885
} else {
1886
dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
1887
strcpy(dsPtr->string, iPtr->result);
1888
(*iPtr->freeProc)(iPtr->result);
1889
}
1890
dsPtr->spaceAvl = dsPtr->length+1;
1891
iPtr->freeProc = NULL;
1892
} else {
1893
if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
1894
dsPtr->string = dsPtr->staticSpace;
1895
dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
1896
} else {
1897
dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
1898
dsPtr->spaceAvl = dsPtr->length + 1;
1899
}
1900
strcpy(dsPtr->string, iPtr->result);
1901
}
1902
iPtr->result = iPtr->resultSpace;
1903
iPtr->resultSpace[0] = 0;
1904
}
1905
1906
/*
1907
*----------------------------------------------------------------------
1908
*
1909
* Tcl_DStringStartSublist --
1910
*
1911
* This procedure adds the necessary information to a dynamic
1912
* string (e.g. " {" to start a sublist. Future element
1913
* appends will be in the sublist rather than the main list.
1914
*
1915
* Results:
1916
* None.
1917
*
1918
* Side effects:
1919
* Characters get added to the dynamic string.
1920
*
1921
*----------------------------------------------------------------------
1922
*/
1923
1924
void
1925
Tcl_DStringStartSublist(dsPtr)
1926
Tcl_DString *dsPtr; /* Dynamic string. */
1927
{
1928
if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
1929
Tcl_DStringAppend(dsPtr, " {", -1);
1930
} else {
1931
Tcl_DStringAppend(dsPtr, "{", -1);
1932
}
1933
}
1934
1935
/*
1936
*----------------------------------------------------------------------
1937
*
1938
* Tcl_DStringEndSublist --
1939
*
1940
* This procedure adds the necessary characters to a dynamic
1941
* string to end a sublist (e.g. "}"). Future element appends
1942
* will be in the enclosing (sub)list rather than the current
1943
* sublist.
1944
*
1945
* Results:
1946
* None.
1947
*
1948
* Side effects:
1949
* None.
1950
*
1951
*----------------------------------------------------------------------
1952
*/
1953
1954
void
1955
Tcl_DStringEndSublist(dsPtr)
1956
Tcl_DString *dsPtr; /* Dynamic string. */
1957
{
1958
Tcl_DStringAppend(dsPtr, "}", -1);
1959
}
1960
1961
/*
1962
*----------------------------------------------------------------------
1963
*
1964
* Tcl_PrintDouble --
1965
*
1966
* Given a floating-point value, this procedure converts it to
1967
* an ASCII string using.
1968
*
1969
* Results:
1970
* The ASCII equivalent of "value" is written at "dst". It is
1971
* written using the current precision, and it is guaranteed to
1972
* contain a decimal point or exponent, so that it looks like
1973
* a floating-point value and not an integer.
1974
*
1975
* Side effects:
1976
* None.
1977
*
1978
*----------------------------------------------------------------------
1979
*/
1980
1981
void
1982
Tcl_PrintDouble(interp, value, dst)
1983
Tcl_Interp *interp; /* Interpreter whose tcl_precision
1984
* variable controls printing. */
1985
double value; /* Value to print as string. */
1986
char *dst; /* Where to store converted value;
1987
* must have at least TCL_DOUBLE_SPACE
1988
* characters. */
1989
{
1990
register char *p;
1991
sprintf(dst, ((Interp *) interp)->pdFormat, value);
1992
1993
/*
1994
* If the ASCII result looks like an integer, add ".0" so that it
1995
* doesn't look like an integer anymore. This prevents floating-point
1996
* values from being converted to integers unintentionally.
1997
*/
1998
1999
for (p = dst; *p != 0; p++) {
2000
if ((*p == '.') || (isalpha(UCHAR(*p)))) {
2001
return;
2002
}
2003
}
2004
p[0] = '.';
2005
p[1] = '0';
2006
p[2] = 0;
2007
}
2008
2009
/*
2010
*----------------------------------------------------------------------
2011
*
2012
* TclPrecTraceProc --
2013
*
2014
* This procedure is invoked whenever the variable "tcl_precision"
2015
* is written.
2016
*
2017
* Results:
2018
* Returns NULL if all went well, or an error message if the
2019
* new value for the variable doesn't make sense.
2020
*
2021
* Side effects:
2022
* If the new value doesn't make sense then this procedure
2023
* undoes the effect of the variable modification. Otherwise
2024
* it modifies the format string that's used by Tcl_PrintDouble.
2025
*
2026
*----------------------------------------------------------------------
2027
*/
2028
2029
/* ARGSUSED */
2030
char *
2031
TclPrecTraceProc(clientData, interp, name1, name2, flags)
2032
ClientData clientData; /* Not used. */
2033
Tcl_Interp *interp; /* Interpreter containing variable. */
2034
char *name1; /* Name of variable. */
2035
char *name2; /* Second part of variable name. */
2036
int flags; /* Information about what happened. */
2037
{
2038
register Interp *iPtr = (Interp *) interp;
2039
char *value, *end;
2040
int prec;
2041
2042
/*
2043
* If the variable is unset, then recreate the trace and restore
2044
* the default value of the format string.
2045
*/
2046
2047
if (flags & TCL_TRACE_UNSETS) {
2048
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
2049
Tcl_TraceVar2(interp, name1, name2,
2050
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
2051
TclPrecTraceProc, clientData);
2052
}
2053
strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
2054
iPtr->pdPrec = DEFAULT_PD_PREC;
2055
return (char *) NULL;
2056
}
2057
2058
value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
2059
if (value == NULL) {
2060
value = "";
2061
}
2062
prec = strtoul(value, &end, 10);
2063
if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
2064
(end == value) || (*end != 0)) {
2065
char oldValue[10];
2066
2067
sprintf(oldValue, "%d", iPtr->pdPrec);
2068
Tcl_SetVar2(interp, name1, name2, oldValue, flags & TCL_GLOBAL_ONLY);
2069
return "improper value for precision";
2070
}
2071
sprintf(iPtr->pdFormat, "%%.%dg", prec);
2072
iPtr->pdPrec = prec;
2073
return (char *) NULL;
2074
}
2075
2076
/*
2077
*----------------------------------------------------------------------
2078
*
2079
* TclNeedSpace --
2080
*
2081
* This procedure checks to see whether it is appropriate to
2082
* add a space before appending a new list element to an
2083
* existing string.
2084
*
2085
* Results:
2086
* The return value is 1 if a space is appropriate, 0 otherwise.
2087
*
2088
* Side effects:
2089
* None.
2090
*
2091
*----------------------------------------------------------------------
2092
*/
2093
2094
int
2095
TclNeedSpace(start, end)
2096
char *start; /* First character in string. */
2097
char *end; /* End of string (place where space will
2098
* be added, if appropriate). */
2099
{
2100
/*
2101
* A space is needed unless either
2102
* (a) we're at the start of the string, or
2103
* (b) the trailing characters of the string consist of one or more
2104
* open curly braces preceded by a space or extending back to
2105
* the beginning of the string.
2106
* (c) the trailing characters of the string consist of a space
2107
* preceded by a character other than backslash.
2108
*/
2109
2110
if (end == start) {
2111
return 0;
2112
}
2113
end--;
2114
if (*end != '{') {
2115
if (isspace(UCHAR(*end)) && ((end == start) || (end[-1] != '\\'))) {
2116
return 0;
2117
}
2118
return 1;
2119
}
2120
do {
2121
if (end == start) {
2122
return 0;
2123
}
2124
end--;
2125
} while (*end == '{');
2126
if (isspace(UCHAR(*end))) {
2127
return 0;
2128
}
2129
return 1;
2130
}
2131
2132