|
|
1.1 root 1: /*
2: * tclUtil.c --
3: *
4: * This file contains utility procedures that are used by many Tcl
5: * commands.
6: *
7: * Copyright 1987-1991 Regents of the University of California
8: * Permission to use, copy, modify, and distribute this
9: * software and its documentation for any purpose and without
10: * fee is hereby granted, provided that the above copyright
11: * notice appear in all copies. The University of California
12: * makes no representations about the suitability of this
13: * software for any purpose. It is provided "as is" without
14: * express or implied warranty.
15: */
16:
17: #ifndef lint
18: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUtil.c,v 1.63 92/07/02 08:50:54 ouster Exp $ SPRITE (Berkeley)";
19: #endif
20:
21: #include "tclint.h"
22:
23: /*
24: * The following values are used in the flags returned by Tcl_ScanElement
25: * and used by Tcl_ConvertElement. The value TCL_DONT_USE_BRACES is also
26: * defined in tcl.h; make sure its value doesn't overlap with any of the
27: * values below.
28: *
29: * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in
30: * braces (e.g. it contains unmatched braces,
31: * or ends in a backslash character, or user
32: * just doesn't want braces); handle all
33: * special characters by adding backslashes.
34: * USE_BRACES - 1 means the string contains a special
35: * character that can be handled simply by
36: * enclosing the entire argument in braces.
37: * BRACES_UNMATCHED - 1 means that braces aren't properly matched
38: * in the argument.
39: */
40:
41: #define USE_BRACES 2
42: #define BRACES_UNMATCHED 4
43:
44: /*
45: * The variable below is set to NULL before invoking regexp functions
46: * and checked after those functions. If an error occurred then regerror
47: * will set the variable to point to a (static) error message. This
48: * mechanism unfortunately does not support multi-threading, but then
49: * neither does the rest of the regexp facilities.
50: */
51:
52: char *tclRegexpError = NULL;
53:
54: /*
55: * Function prototypes for local procedures in this file:
56: */
57:
58: static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
59: int newSpace));
60:
61: /*
62: *----------------------------------------------------------------------
63: *
64: * TclFindElement --
65: *
66: * Given a pointer into a Tcl list, locate the first (or next)
67: * element in the list.
68: *
69: * Results:
70: * The return value is normally TCL_OK, which means that the
71: * element was successfully located. If TCL_ERROR is returned
72: * it means that list didn't have proper list structure;
73: * interp->result contains a more detailed error message.
74: *
75: * If TCL_OK is returned, then *elementPtr will be set to point
76: * to the first element of list, and *nextPtr will be set to point
77: * to the character just after any white space following the last
78: * character that's part of the element. If this is the last argument
79: * in the list, then *nextPtr will point to the NULL character at the
80: * end of list. If sizePtr is non-NULL, *sizePtr is filled in with
81: * the number of characters in the element. If the element is in
82: * braces, then *elementPtr will point to the character after the
83: * opening brace and *sizePtr will not include either of the braces.
84: * If there isn't an element in the list, *sizePtr will be zero, and
85: * both *elementPtr and *termPtr will refer to the null character at
86: * the end of list. Note: this procedure does NOT collapse backslash
87: * sequences.
88: *
89: * Side effects:
90: * None.
91: *
92: *----------------------------------------------------------------------
93: */
94:
95: int
96: TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
97: Tcl_Interp *interp; /* Interpreter to use for error reporting. */
98: register char *list; /* String containing Tcl list with zero
99: * or more elements (possibly in braces). */
100: char **elementPtr; /* Fill in with location of first significant
101: * character in first element of list. */
102: char **nextPtr; /* Fill in with location of character just
103: * after all white space following end of
104: * argument (i.e. next argument or end of
105: * list). */
106: int *sizePtr; /* If non-zero, fill in with size of
107: * element. */
108: int *bracePtr; /* If non-zero fill in with non-zero/zero
109: * to indicate that arg was/wasn't
110: * in braces. */
111: {
112: register char *p;
113: int openBraces = 0;
114: int inQuotes = 0;
115: int size;
116:
117: /*
118: * Skim off leading white space and check for an opening brace or
119: * quote. Note: use of "isascii" below and elsewhere in this
120: * procedure is a temporary workaround (7/27/90) because Mx uses characters
121: * with the high-order bit set for some things. This should probably
122: * be changed back eventually, or all of Tcl should call isascii.
123: */
124:
125: while (isascii(*list) && isspace(*list)) {
126: list++;
127: }
128: if (*list == '{') {
129: openBraces = 1;
130: list++;
131: } else if (*list == '"') {
132: inQuotes = 1;
133: list++;
134: }
135: if (bracePtr != 0) {
136: *bracePtr = openBraces;
137: }
138: p = list;
139:
140: /*
141: * Find the end of the element (either a space or a close brace or
142: * the end of the string).
143: */
144:
145: while (1) {
146: switch (*p) {
147:
148: /*
149: * Open brace: don't treat specially unless the element is
150: * in braces. In this case, keep a nesting count.
151: */
152:
153: case '{':
154: if (openBraces != 0) {
155: openBraces++;
156: }
157: break;
158:
159: /*
160: * Close brace: if element is in braces, keep nesting
161: * count and quit when the last close brace is seen.
162: */
163:
164: case '}':
165: if (openBraces == 1) {
166: char *p2;
167:
168: size = p - list;
169: p++;
170: if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
171: goto done;
172: }
173: for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
174: p2++) {
175: /* null body */
176: }
177: Tcl_ResetResult(interp);
178: sprintf(interp->result,
179: "list element in braces followed by \"%.*s\" instead of space",
180: p2-p, p);
181: return TCL_ERROR;
182: } else if (openBraces != 0) {
183: openBraces--;
184: }
185: break;
186:
187: /*
188: * Backslash: skip over everything up to the end of the
189: * backslash sequence.
190: */
191:
192: case '\\': {
193: int size;
194:
195: (void) Tcl_Backslash(p, &size);
196: p += size - 1;
197: break;
198: }
199:
200: /*
201: * Space: ignore if element is in braces or quotes; otherwise
202: * terminate element.
203: */
204:
205: case ' ':
206: case '\f':
207: case '\n':
208: case '\r':
209: case '\t':
210: case '\v':
211: if ((openBraces == 0) && !inQuotes) {
212: size = p - list;
213: goto done;
214: }
215: break;
216:
217: /*
218: * Double-quote: if element is in quotes then terminate it.
219: */
220:
221: case '"':
222: if (inQuotes) {
223: char *p2;
224:
225: size = p-list;
226: p++;
227: if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
228: goto done;
229: }
230: for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
231: p2++) {
232: /* null body */
233: }
234: Tcl_ResetResult(interp);
235: sprintf(interp->result,
236: "list element in quotes followed by \"%.*s\" %s",
237: p2-p, p, "instead of space");
238: return TCL_ERROR;
239: }
240: break;
241:
242: /*
243: * End of list: terminate element.
244: */
245:
246: case 0:
247: if (openBraces != 0) {
248: Tcl_SetResult(interp, "unmatched open brace in list",
249: TCL_STATIC);
250: return TCL_ERROR;
251: } else if (inQuotes) {
252: Tcl_SetResult(interp, "unmatched open quote in list",
253: TCL_STATIC);
254: return TCL_ERROR;
255: }
256: size = p - list;
257: goto done;
258:
259: }
260: p++;
261: }
262:
263: done:
264: while (isascii(*p) && isspace(*p)) {
265: p++;
266: }
267: *elementPtr = list;
268: *nextPtr = p;
269: if (sizePtr != 0) {
270: *sizePtr = size;
271: }
272: return TCL_OK;
273: }
274:
275: /*
276: *----------------------------------------------------------------------
277: *
278: * TclCopyAndCollapse --
279: *
280: * Copy a string and eliminate any backslashes that aren't in braces.
281: *
282: * Results:
283: * There is no return value. Count chars. get copied from src
284: * to dst. Along the way, if backslash sequences are found outside
285: * braces, the backslashes are eliminated in the copy.
286: * After scanning count chars. from source, a null character is
287: * placed at the end of dst.
288: *
289: * Side effects:
290: * None.
291: *
292: *----------------------------------------------------------------------
293: */
294:
295: void
296: TclCopyAndCollapse(count, src, dst)
297: int count; /* Total number of characters to copy
298: * from src. */
299: register char *src; /* Copy from here... */
300: register char *dst; /* ... to here. */
301: {
302: register char c;
303: int numRead;
304:
305: for (c = *src; count > 0; src++, c = *src, count--) {
306: if (c == '\\') {
307: *dst = Tcl_Backslash(src, &numRead);
308: if (*dst != 0) {
309: dst++;
310: }
311: src += numRead-1;
312: count -= numRead-1;
313: } else {
314: *dst = c;
315: dst++;
316: }
317: }
318: *dst = 0;
319: }
320:
321: /*
322: *----------------------------------------------------------------------
323: *
324: * Tcl_SplitList --
325: *
326: * Splits a list up into its constituent fields.
327: *
328: * Results
329: * The return value is normally TCL_OK, which means that
330: * the list was successfully split up. If TCL_ERROR is
331: * returned, it means that "list" didn't have proper list
332: * structure; interp->result will contain a more detailed
333: * error message.
334: *
335: * *argvPtr will be filled in with the address of an array
336: * whose elements point to the elements of list, in order.
337: * *argcPtr will get filled in with the number of valid elements
338: * in the array. A single block of memory is dynamically allocated
339: * to hold both the argv array and a copy of the list (with
340: * backslashes and braces removed in the standard way).
341: * The caller must eventually free this memory by calling free()
342: * on *argvPtr. Note: *argvPtr and *argcPtr are only modified
343: * if the procedure returns normally.
344: *
345: * Side effects:
346: * Memory is allocated.
347: *
348: *----------------------------------------------------------------------
349: */
350:
351: int
352: Tcl_SplitList(interp, list, argcPtr, argvPtr)
353: Tcl_Interp *interp; /* Interpreter to use for error reporting. */
354: char *list; /* Pointer to string with list structure. */
355: int *argcPtr; /* Pointer to location to fill in with
356: * the number of elements in the list. */
357: char ***argvPtr; /* Pointer to place to store pointer to array
358: * of pointers to list elements. */
359: {
360: char **argv;
361: register char *p;
362: int size, i, result, elSize, brace;
363: char *element;
364:
365: /*
366: * Figure out how much space to allocate. There must be enough
367: * space for both the array of pointers and also for a copy of
368: * the list. To estimate the number of pointers needed, count
369: * the number of space characters in the list.
370: */
371:
372: for (size = 1, p = list; *p != 0; p++) {
373: if (isspace(*p)) {
374: size++;
375: }
376: }
377: size++; /* Leave space for final NULL pointer. */
378: argv = (char **) ckalloc((unsigned)
379: ((size * sizeof(char *)) + (p - list) + 1));
380: for (i = 0, p = ((char *) argv) + size*sizeof(char *);
381: *list != 0; i++) {
382: result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
383: if (result != TCL_OK) {
384: ckfree((char *) argv);
385: return result;
386: }
387: if (*element == 0) {
388: break;
389: }
390: if (i >= size) {
391: ckfree((char *) argv);
392: Tcl_SetResult(interp, "internal error in Tcl_SplitList",
393: TCL_STATIC);
394: return TCL_ERROR;
395: }
396: argv[i] = p;
397: if (brace) {
398: strncpy(p, element, elSize);
399: p += elSize;
400: *p = 0;
401: p++;
402: } else {
403: TclCopyAndCollapse(elSize, element, p);
404: p += elSize+1;
405: }
406: }
407:
408: argv[i] = NULL;
409: *argvPtr = argv;
410: *argcPtr = i;
411: return TCL_OK;
412: }
413:
414: /*
415: *----------------------------------------------------------------------
416: *
417: * Tcl_ScanElement --
418: *
419: * This procedure is a companion procedure to Tcl_ConvertElement.
420: * It scans a string to see what needs to be done to it (e.g.
421: * add backslashes or enclosing braces) to make the string into
422: * a valid Tcl list element.
423: *
424: * Results:
425: * The return value is an overestimate of the number of characters
426: * that will be needed by Tcl_ConvertElement to produce a valid
427: * list element from string. The word at *flagPtr is filled in
428: * with a value needed by Tcl_ConvertElement when doing the actual
429: * conversion.
430: *
431: * Side effects:
432: * None.
433: *
434: *----------------------------------------------------------------------
435: */
436:
437: int
438: Tcl_ScanElement(string, flagPtr)
439: char *string; /* String to convert to Tcl list element. */
440: int *flagPtr; /* Where to store information to guide
441: * Tcl_ConvertElement. */
442: {
443: int flags, nestingLevel;
444: register char *p;
445:
446: /*
447: * This procedure and Tcl_ConvertElement together do two things:
448: *
449: * 1. They produce a proper list, one that will yield back the
450: * argument strings when evaluated or when disassembled with
451: * Tcl_SplitList. This is the most important thing.
452: *
453: * 2. They try to produce legible output, which means minimizing the
454: * use of backslashes (using braces instead). However, there are
455: * some situations where backslashes must be used (e.g. an element
456: * like "{abc": the leading brace will have to be backslashed. For
457: * each element, one of three things must be done:
458: *
459: * (a) Use the element as-is (it doesn't contain anything special
460: * characters). This is the most desirable option.
461: *
462: * (b) Enclose the element in braces, but leave the contents alone.
463: * This happens if the element contains embedded space, or if it
464: * contains characters with special interpretation ($, [, ;, or \),
465: * or if it starts with a brace or double-quote, or if there are
466: * no characters in the element.
467: *
468: * (c) Don't enclose the element in braces, but add backslashes to
469: * prevent special interpretation of special characters. This is a
470: * last resort used when the argument would normally fall under case
471: * (b) but contains unmatched braces. It also occurs if the last
472: * character of the argument is a backslash.
473: *
474: * The procedure figures out how many bytes will be needed to store
475: * the result (actually, it overestimates). It also collects information
476: * about the element in the form of a flags word.
477: */
478:
479: nestingLevel = 0;
480: flags = 0;
481: p = string;
482: if ((*p == '{') || (*p == '"') || (*p == 0)) {
483: flags |= USE_BRACES;
484: }
485: for ( ; *p != 0; p++) {
486: switch (*p) {
487: case '{':
488: nestingLevel++;
489: break;
490: case '}':
491: nestingLevel--;
492: if (nestingLevel < 0) {
493: flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
494: }
495: break;
496: case '[':
497: case '$':
498: case ';':
499: case ' ':
500: case '\f':
501: case '\n':
502: case '\r':
503: case '\t':
504: case '\v':
505: flags |= USE_BRACES;
506: break;
507: case '\\':
508: if (p[1] == 0) {
509: flags = TCL_DONT_USE_BRACES;
510: } else {
511: int size;
512:
513: (void) Tcl_Backslash(p, &size);
514: p += size-1;
515: flags |= USE_BRACES;
516: }
517: break;
518: }
519: }
520: if (nestingLevel != 0) {
521: flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
522: }
523: *flagPtr = flags;
524:
525: /*
526: * Allow enough space to backslash every character plus leave
527: * two spaces for braces.
528: */
529:
530: return 2*(p-string) + 2;
531: }
532:
533: /*
534: *----------------------------------------------------------------------
535: *
536: * Tcl_ConvertElement --
537: *
538: * This is a companion procedure to Tcl_ScanElement. Given the
539: * information produced by Tcl_ScanElement, this procedure converts
540: * a string to a list element equal to that string.
541: *
542: * Results:
543: * Information is copied to *dst in the form of a list element
544: * identical to src (i.e. if Tcl_SplitList is applied to dst it
545: * will produce a string identical to src). The return value is
546: * a count of the number of characters copied (not including the
547: * terminating NULL character).
548: *
549: * Side effects:
550: * None.
551: *
552: *----------------------------------------------------------------------
553: */
554:
555: int
556: Tcl_ConvertElement(src, dst, flags)
557: register char *src; /* Source information for list element. */
558: char *dst; /* Place to put list-ified element. */
559: int flags; /* Flags produced by Tcl_ScanElement. */
560: {
561: register char *p = dst;
562:
563: /*
564: * See the comment block at the beginning of the Tcl_ScanElement
565: * code for details of how this works.
566: */
567:
568: if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
569: *p = '{';
570: p++;
571: for ( ; *src != 0; src++, p++) {
572: *p = *src;
573: }
574: *p = '}';
575: p++;
576: } else if (*src == 0) {
577: /*
578: * If string is empty but can't use braces, then use special
579: * backslash sequence that maps to empty string.
580: */
581:
582: p[0] = '\\';
583: p[1] = '0';
584: p += 2;
585: } else {
586: for (; *src != 0 ; src++) {
587: switch (*src) {
588: case ']':
589: case '[':
590: case '$':
591: case ';':
592: case ' ':
593: case '\\':
594: case '"':
595: *p = '\\';
596: p++;
597: break;
598: case '{':
599: case '}':
600: if (flags & BRACES_UNMATCHED) {
601: *p = '\\';
602: p++;
603: }
604: break;
605: case '\f':
606: *p = '\\';
607: p++;
608: *p = 'f';
609: p++;
610: continue;
611: case '\n':
612: *p = '\\';
613: p++;
614: *p = 'n';
615: p++;
616: continue;
617: case '\r':
618: *p = '\\';
619: p++;
620: *p = 'r';
621: p++;
622: continue;
623: case '\t':
624: *p = '\\';
625: p++;
626: *p = 't';
627: p++;
628: continue;
629: case '\v':
630: *p = '\\';
631: p++;
632: *p = 'v';
633: p++;
634: continue;
635: }
636: *p = *src;
637: p++;
638: }
639: }
640: *p = '\0';
641: return p-dst;
642: }
643:
644: /*
645: *----------------------------------------------------------------------
646: *
647: * Tcl_Merge --
648: *
649: * Given a collection of strings, merge them together into a
650: * single string that has proper Tcl list structured (i.e.
651: * Tcl_SplitList may be used to retrieve strings equal to the
652: * original elements, and Tcl_Eval will parse the string back
653: * into its original elements).
654: *
655: * Results:
656: * The return value is the address of a dynamically-allocated
657: * string containing the merged list.
658: *
659: * Side effects:
660: * None.
661: *
662: *----------------------------------------------------------------------
663: */
664:
665: char *
666: Tcl_Merge(argc, argv)
667: int argc; /* How many strings to merge. */
668: char **argv; /* Array of string values. */
669: {
670: # define LOCAL_SIZE 20
671: int localFlags[LOCAL_SIZE], *flagPtr;
672: int numChars;
673: char *result;
674: register char *dst;
675: int i;
676:
677: /*
678: * Pass 1: estimate space, gather flags.
679: */
680:
681: if (argc <= LOCAL_SIZE) {
682: flagPtr = localFlags;
683: } else {
684: flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
685: }
686: numChars = 1;
687: for (i = 0; i < argc; i++) {
688: numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
689: }
690:
691: /*
692: * Pass two: copy into the result area.
693: */
694:
695: result = (char *) ckalloc((unsigned) numChars);
696: dst = result;
697: for (i = 0; i < argc; i++) {
698: numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
699: dst += numChars;
700: *dst = ' ';
701: dst++;
702: }
703: if (dst == result) {
704: *dst = 0;
705: } else {
706: dst[-1] = 0;
707: }
708:
709: if (flagPtr != localFlags) {
710: ckfree((char *) flagPtr);
711: }
712: return result;
713: }
714:
715: /*
716: *----------------------------------------------------------------------
717: *
718: * Tcl_Concat --
719: *
720: * Concatenate a set of strings into a single large string.
721: *
722: * Results:
723: * The return value is dynamically-allocated string containing
724: * a concatenation of all the strings in argv, with spaces between
725: * the original argv elements.
726: *
727: * Side effects:
728: * Memory is allocated for the result; the caller is responsible
729: * for freeing the memory.
730: *
731: *----------------------------------------------------------------------
732: */
733:
734: char *
735: Tcl_Concat(argc, argv)
736: int argc; /* Number of strings to concatenate. */
737: char **argv; /* Array of strings to concatenate. */
738: {
739: int totalSize, i;
740: register char *p;
741: char *result;
742:
743: for (totalSize = 1, i = 0; i < argc; i++) {
744: totalSize += strlen(argv[i]) + 1;
745: }
746: result = (char *) ckalloc((unsigned) totalSize);
747: if (argc == 0) {
748: *result = '\0';
749: return result;
750: }
751: for (p = result, i = 0; i < argc; i++) {
752: char *element;
753: int length;
754:
755: /*
756: * Clip white space off the front and back of the string
757: * to generate a neater result, and ignore any empty
758: * elements.
759: */
760:
761: element = argv[i];
762: while (isspace(*element)) {
763: element++;
764: }
765: for (length = strlen(element);
766: (length > 0) && (isspace(element[length-1]));
767: length--) {
768: /* Null loop body. */
769: }
770: if (length == 0) {
771: continue;
772: }
773: (void) strncpy(p, element, length);
774: p += length;
775: *p = ' ';
776: p++;
777: }
778: if (p != result) {
779: p[-1] = 0;
780: } else {
781: *p = 0;
782: }
783: return result;
784: }
785:
786: /*
787: *----------------------------------------------------------------------
788: *
789: * Tcl_StringMatch --
790: *
791: * See if a particular string matches a particular pattern.
792: *
793: * Results:
794: * The return value is 1 if string matches pattern, and
795: * 0 otherwise. The matching operation permits the following
796: * special characters in the pattern: *?\[] (see the manual
797: * entry for details on what these mean).
798: *
799: * Side effects:
800: * None.
801: *
802: *----------------------------------------------------------------------
803: */
804:
805: int
806: Tcl_StringMatch(string, pattern)
807: register char *string; /* String. */
808: register char *pattern; /* Pattern, which may contain
809: * special characters. */
810: {
811: char c2;
812:
813: while (1) {
814: /* See if we're at the end of both the pattern and the string.
815: * If so, we succeeded. If we're at the end of the pattern
816: * but not at the end of the string, we failed.
817: */
818:
819: if (*pattern == 0) {
820: if (*string == 0) {
821: return 1;
822: } else {
823: return 0;
824: }
825: }
826: if ((*string == 0) && (*pattern != '*')) {
827: return 0;
828: }
829:
830: /* Check for a "*" as the next pattern character. It matches
831: * any substring. We handle this by calling ourselves
832: * recursively for each postfix of string, until either we
833: * match or we reach the end of the string.
834: */
835:
836: if (*pattern == '*') {
837: pattern += 1;
838: if (*pattern == 0) {
839: return 1;
840: }
841: while (1) {
842: if (Tcl_StringMatch(string, pattern)) {
843: return 1;
844: }
845: if (*string == 0) {
846: return 0;
847: }
848: string += 1;
849: }
850: }
851:
852: /* Check for a "?" as the next pattern character. It matches
853: * any single character.
854: */
855:
856: if (*pattern == '?') {
857: goto thisCharOK;
858: }
859:
860: /* Check for a "[" as the next pattern character. It is followed
861: * by a list of characters that are acceptable, or by a range
862: * (two characters separated by "-").
863: */
864:
865: if (*pattern == '[') {
866: pattern += 1;
867: while (1) {
868: if ((*pattern == ']') || (*pattern == 0)) {
869: return 0;
870: }
871: if (*pattern == *string) {
872: break;
873: }
874: if (pattern[1] == '-') {
875: c2 = pattern[2];
876: if (c2 == 0) {
877: return 0;
878: }
879: if ((*pattern <= *string) && (c2 >= *string)) {
880: break;
881: }
882: if ((*pattern >= *string) && (c2 <= *string)) {
883: break;
884: }
885: pattern += 2;
886: }
887: pattern += 1;
888: }
889: while ((*pattern != ']') && (*pattern != 0)) {
890: pattern += 1;
891: }
892: goto thisCharOK;
893: }
894:
895: /* If the next pattern character is '/', just strip off the '/'
896: * so we do exact matching on the character that follows.
897: */
898:
899: if (*pattern == '\\') {
900: pattern += 1;
901: if (*pattern == 0) {
902: return 0;
903: }
904: }
905:
906: /* There's no special character. Just make sure that the next
907: * characters of each string match.
908: */
909:
910: if (*pattern != *string) {
911: return 0;
912: }
913:
914: thisCharOK: pattern += 1;
915: string += 1;
916: }
917: }
918:
919: /*
920: *----------------------------------------------------------------------
921: *
922: * Tcl_SetResult --
923: *
924: * Arrange for "string" to be the Tcl return value.
925: *
926: * Results:
927: * None.
928: *
929: * Side effects:
930: * interp->result is left pointing either to "string" (if "copy" is 0)
931: * or to a copy of string.
932: *
933: *----------------------------------------------------------------------
934: */
935:
936: void
937: Tcl_SetResult(interp, string, freeProc)
938: Tcl_Interp *interp; /* Interpreter with which to associate the
939: * return value. */
940: char *string; /* Value to be returned. If NULL,
941: * the result is set to an empty string. */
942: Tcl_FreeProc *freeProc; /* Gives information about the string:
943: * TCL_STATIC, TCL_VOLATILE, or the address
944: * of a Tcl_FreeProc such as free. */
945: {
946: register Interp *iPtr = (Interp *) interp;
947: int length;
948: Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
949: char *oldResult = iPtr->result;
950:
951: iPtr->freeProc = freeProc;
952: if (string == NULL) {
953: iPtr->resultSpace[0] = 0;
954: iPtr->result = iPtr->resultSpace;
955: iPtr->freeProc = 0;
956: } else if (freeProc == TCL_VOLATILE) {
957: length = strlen(string);
958: if (length > TCL_RESULT_SIZE) {
959: iPtr->result = (char *) ckalloc((unsigned) length+1);
960: iPtr->freeProc = (Tcl_FreeProc *) free;
961: } else {
962: iPtr->result = iPtr->resultSpace;
963: iPtr->freeProc = 0;
964: }
965: strcpy(iPtr->result, string);
966: } else {
967: iPtr->result = string;
968: }
969:
970: /*
971: * If the old result was dynamically-allocated, free it up. Do it
972: * here, rather than at the beginning, in case the new result value
973: * was part of the old result value.
974: */
975:
976: if (oldFreeProc != 0) {
977: (*oldFreeProc)(oldResult);
978: }
979: }
980:
981: /*
982: *----------------------------------------------------------------------
983: *
984: * Tcl_AppendResult --
985: *
986: * Append a variable number of strings onto the result already
987: * present for an interpreter.
988: *
989: * Results:
990: * None.
991: *
992: * Side effects:
993: * The result in the interpreter given by the first argument
994: * is extended by the strings given by the second and following
995: * arguments (up to a terminating NULL argument).
996: *
997: *----------------------------------------------------------------------
998: */
999:
1000: void
1001: Tcl_AppendResult(Tcl_Interp *interp, ...)
1002: {
1003: va_list argList;
1004: register Interp *iPtr;
1005: char *string;
1006: int newSpace;
1007:
1008: /*
1009: * First, scan through all the arguments to see how much space is
1010: * needed.
1011: */
1012:
1013: va_start(argList, interp);
1014: iPtr = (Interp *)interp;
1015: newSpace = 0;
1016: while (1) {
1017: string = va_arg(argList, char *);
1018: if (string == NULL) {
1019: break;
1020: }
1021: newSpace += strlen(string);
1022: }
1023: va_end(argList);
1024:
1025: /*
1026: * If the append buffer isn't already setup and large enough
1027: * to hold the new data, set it up.
1028: */
1029:
1030: if ((iPtr->result != iPtr->appendResult)
1031: || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
1032: SetupAppendBuffer(iPtr, newSpace);
1033: }
1034:
1035: /*
1036: * Final step: go through all the argument strings again, copying
1037: * them into the buffer.
1038: */
1039:
1040: va_start(argList, interp);
1041: while (1) {
1042: string = va_arg(argList, char *);
1043: if (string == NULL) {
1044: break;
1045: }
1046: strcpy(iPtr->appendResult + iPtr->appendUsed, string);
1047: iPtr->appendUsed += strlen(string);
1048: }
1049: va_end(argList);
1050: }
1051:
1052: /*
1053: *----------------------------------------------------------------------
1054: *
1055: * Tcl_AppendElement --
1056: *
1057: * Convert a string to a valid Tcl list element and append it
1058: * to the current result (which is ostensibly a list).
1059: *
1060: * Results:
1061: * None.
1062: *
1063: * Side effects:
1064: * The result in the interpreter given by the first argument
1065: * is extended with a list element converted from string. If
1066: * the original result wasn't empty, then a blank is added before
1067: * the converted list element.
1068: *
1069: *----------------------------------------------------------------------
1070: */
1071:
1072: void
1073: Tcl_AppendElement(interp, string, noSep)
1074: Tcl_Interp *interp; /* Interpreter whose result is to be
1075: * extended. */
1076: char *string; /* String to convert to list element and
1077: * add to result. */
1078: int noSep; /* If non-zero, then don't output a
1079: * space character before this element,
1080: * even if the element isn't the first
1081: * thing in the output buffer. */
1082: {
1083: register Interp *iPtr = (Interp *) interp;
1084: int size, flags;
1085: char *dst;
1086:
1087: /*
1088: * See how much space is needed, and grow the append buffer if
1089: * needed to accommodate the list element.
1090: */
1091:
1092: size = Tcl_ScanElement(string, &flags) + 1;
1093: if ((iPtr->result != iPtr->appendResult)
1094: || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
1095: SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
1096: }
1097:
1098: /*
1099: * Convert the string into a list element and copy it to the
1100: * buffer that's forming.
1101: */
1102:
1103: dst = iPtr->appendResult + iPtr->appendUsed;
1104: if (!noSep && (iPtr->appendUsed != 0)) {
1105: iPtr->appendUsed++;
1106: *dst = ' ';
1107: dst++;
1108: }
1109: iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
1110: }
1111:
1112: /*
1113: *----------------------------------------------------------------------
1114: *
1115: * SetupAppendBuffer --
1116: *
1117: * This procedure makes sure that there is an append buffer
1118: * properly initialized for interp, and that it has at least
1119: * enough room to accommodate newSpace new bytes of information.
1120: *
1121: * Results:
1122: * None.
1123: *
1124: * Side effects:
1125: * None.
1126: *
1127: *----------------------------------------------------------------------
1128: */
1129:
1130: static void
1131: SetupAppendBuffer(iPtr, newSpace)
1132: register Interp *iPtr; /* Interpreter whose result is being set up. */
1133: int newSpace; /* Make sure that at least this many bytes
1134: * of new information may be added. */
1135: {
1136: int totalSpace;
1137:
1138: /*
1139: * Make the append buffer larger, if that's necessary, then
1140: * copy the current result into the append buffer and make the
1141: * append buffer the official Tcl result.
1142: */
1143:
1144: if (iPtr->result != iPtr->appendResult) {
1145: /*
1146: * If an oversized buffer was used recently, then free it up
1147: * so we go back to a smaller buffer. This avoids tying up
1148: * memory forever after a large operation.
1149: */
1150:
1151: if (iPtr->appendAvl > 500) {
1152: ckfree(iPtr->appendResult);
1153: iPtr->appendResult = NULL;
1154: iPtr->appendAvl = 0;
1155: }
1156: iPtr->appendUsed = strlen(iPtr->result);
1157: }
1158: totalSpace = newSpace + iPtr->appendUsed;
1159: if (totalSpace >= iPtr->appendAvl) {
1160: char *new;
1161:
1162: if (totalSpace < 100) {
1163: totalSpace = 200;
1164: } else {
1165: totalSpace *= 2;
1166: }
1167: new = (char *) ckalloc((unsigned) totalSpace);
1168: strcpy(new, iPtr->result);
1169: if (iPtr->appendResult != NULL) {
1170: ckfree(iPtr->appendResult);
1171: }
1172: iPtr->appendResult = new;
1173: iPtr->appendAvl = totalSpace;
1174: } else if (iPtr->result != iPtr->appendResult) {
1175: strcpy(iPtr->appendResult, iPtr->result);
1176: }
1177: Tcl_FreeResult(iPtr);
1178: iPtr->result = iPtr->appendResult;
1179: }
1180:
1181: /*
1182: *----------------------------------------------------------------------
1183: *
1184: * Tcl_ResetResult --
1185: *
1186: * This procedure restores the result area for an interpreter
1187: * to its default initialized state, freeing up any memory that
1188: * may have been allocated for the result and clearing any
1189: * error information for the interpreter.
1190: *
1191: * Results:
1192: * None.
1193: *
1194: * Side effects:
1195: * None.
1196: *
1197: *----------------------------------------------------------------------
1198: */
1199:
1200: void
1201: Tcl_ResetResult(interp)
1202: Tcl_Interp *interp; /* Interpreter for which to clear result. */
1203: {
1204: register Interp *iPtr = (Interp *) interp;
1205:
1206: Tcl_FreeResult(iPtr);
1207: iPtr->result = iPtr->resultSpace;
1208: iPtr->resultSpace[0] = 0;
1209: iPtr->flags &=
1210: ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
1211: }
1212:
1213: /*
1214: *----------------------------------------------------------------------
1215: *
1216: * Tcl_SetErrorCode --
1217: *
1218: * This procedure is called to record machine-readable information
1219: * about an error that is about to be returned.
1220: *
1221: * Results:
1222: * None.
1223: *
1224: * Side effects:
1225: * The errorCode global variable is modified to hold all of the
1226: * arguments to this procedure, in a list form with each argument
1227: * becoming one element of the list. A flag is set internally
1228: * to remember that errorCode has been set, so the variable doesn't
1229: * get set automatically when the error is returned.
1230: *
1231: *----------------------------------------------------------------------
1232: */
1233: void
1234: Tcl_SetErrorCode(Tcl_Interp *interp, ...)
1235: {
1236: va_list argList;
1237: char *string;
1238: int flags;
1239: Interp *iPtr;
1240:
1241: /*
1242: * Scan through the arguments one at a time, appending them to
1243: * $errorCode as list elements.
1244: */
1245:
1246: va_start(argList, interp);
1247: iPtr = (Interp *)interp;
1248: flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
1249: while (1) {
1250: string = va_arg(argList, char *);
1251: if (string == NULL) {
1252: break;
1253: }
1254: (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
1255: (char *) NULL, string, flags);
1256: flags |= TCL_APPEND_VALUE;
1257: }
1258: va_end(argList);
1259: iPtr->flags |= ERROR_CODE_SET;
1260: }
1261:
1262: /*
1263: *----------------------------------------------------------------------
1264: *
1265: * TclGetListIndex --
1266: *
1267: * Parse a list index, which may be either an integer or the
1268: * value "end".
1269: *
1270: * Results:
1271: * The return value is either TCL_OK or TCL_ERROR. If it is
1272: * TCL_OK, then the index corresponding to string is left in
1273: * *indexPtr. If the return value is TCL_ERROR, then string
1274: * was bogus; an error message is returned in interp->result.
1275: * If a negative index is specified, it is rounded up to 0.
1276: * The index value may be larger than the size of the list
1277: * (this happens when "end" is specified).
1278: *
1279: * Side effects:
1280: * None.
1281: *
1282: *----------------------------------------------------------------------
1283: */
1284:
1285: int
1286: TclGetListIndex(interp, string, indexPtr)
1287: Tcl_Interp *interp; /* Interpreter for error reporting. */
1288: char *string; /* String containing list index. */
1289: int *indexPtr; /* Where to store index. */
1290: {
1291: if (isdigit(*string) || (*string == '-')) {
1292: if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
1293: return TCL_ERROR;
1294: }
1295: if (*indexPtr < 0) {
1296: *indexPtr = 0;
1297: }
1298: } else if (strncmp(string, "end", strlen(string)) == 0) {
1299: *indexPtr = 1<<30;
1300: } else {
1301: Tcl_AppendResult(interp, "bad index \"", string,
1302: "\": must be integer or \"end\"", (char *) NULL);
1303: return TCL_ERROR;
1304: }
1305: return TCL_OK;
1306: }
1307:
1308: /*
1309: *----------------------------------------------------------------------
1310: *
1311: * TclCompileRegexp --
1312: *
1313: * Compile a regular expression into a form suitable for fast
1314: * matching. This procedure retains a small cache of pre-compiled
1315: * regular expressions in the interpreter, in order to avoid
1316: * compilation costs as much as possible.
1317: *
1318: * Results:
1319: * The return value is a pointer to the compiled form of string,
1320: * suitable for passing to regexec. If an error occurred while
1321: * compiling the pattern, then NULL is returned and an error
1322: * message is left in interp->result.
1323: *
1324: * Side effects:
1325: * The cache of compiled regexp's in interp will be modified to
1326: * hold information for string, if such information isn't already
1327: * present in the cache.
1328: *
1329: *----------------------------------------------------------------------
1330: */
1331:
1332: regexp *
1333: TclCompileRegexp(interp, string)
1334: Tcl_Interp *interp; /* For use in error reporting. */
1335: char *string; /* String for which to produce
1336: * compiled regular expression. */
1337: {
1338: register Interp *iPtr = (Interp *) interp;
1339: int i, length;
1340: regexp *result;
1341:
1342: length = strlen(string);
1343: for (i = 0; i < NUM_REGEXPS; i++) {
1344: if ((length == iPtr->patLengths[i])
1345: && (strcmp(string, iPtr->patterns[i]) == 0)) {
1346: /*
1347: * Move the matched pattern to the first slot in the
1348: * cache and shift the other patterns down one position.
1349: */
1350:
1351: if (i != 0) {
1352: int j;
1353: char *cachedString;
1354:
1355: cachedString = iPtr->patterns[i];
1356: result = iPtr->regexps[i];
1357: for (j = i-1; j >= 0; j--) {
1358: iPtr->patterns[j+1] = iPtr->patterns[j];
1359: iPtr->patLengths[j+1] = iPtr->patLengths[j];
1360: iPtr->regexps[j+1] = iPtr->regexps[j];
1361: }
1362: iPtr->patterns[0] = cachedString;
1363: iPtr->patLengths[0] = length;
1364: iPtr->regexps[0] = result;
1365: }
1366: return iPtr->regexps[0];
1367: }
1368: }
1369:
1370: /*
1371: * No match in the cache. Compile the string and add it to the
1372: * cache.
1373: */
1374:
1375: tclRegexpError = NULL;
1376: result = regcomp(string);
1377: if (tclRegexpError != NULL) {
1378: Tcl_AppendResult(interp,
1379: "couldn't compile regular expression pattern: ",
1380: tclRegexpError, (char *) NULL);
1381: return NULL;
1382: }
1383: if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
1384: ckfree(iPtr->patterns[NUM_REGEXPS-1]);
1385: ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
1386: }
1387: for (i = NUM_REGEXPS - 2; i >= 0; i--) {
1388: iPtr->patterns[i+1] = iPtr->patterns[i];
1389: iPtr->patLengths[i+1] = iPtr->patLengths[i];
1390: iPtr->regexps[i+1] = iPtr->regexps[i];
1391: }
1392: iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
1393: strcpy(iPtr->patterns[0], string);
1394: iPtr->patLengths[0] = length;
1395: iPtr->regexps[0] = result;
1396: return result;
1397: }
1398:
1399: /*
1400: *----------------------------------------------------------------------
1401: *
1402: * regerror --
1403: *
1404: * This procedure is invoked by the Henry Spencer's regexp code
1405: * when an error occurs. It saves the error message so it can
1406: * be seen by the code that called Spencer's code.
1407: *
1408: * Results:
1409: * None.
1410: *
1411: * Side effects:
1412: * The value of "string" is saved in "tclRegexpError".
1413: *
1414: *----------------------------------------------------------------------
1415: */
1416:
1417: void
1418: regerror(string)
1419: char *string; /* Error message. */
1420: {
1421: tclRegexpError = string;
1422: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.