|
|
1.1 root 1: /*
2: * tclCmdAH.c --
3: *
4: * This file contains the top-level command routines for most of
5: * the Tcl built-in commands whose names begin with the letters
6: * A to H.
7: *
8: * Copyright 1987-1991 Regents of the University of California
9: * Permission to use, copy, modify, and distribute this
10: * software and its documentation for any purpose and without
11: * fee is hereby granted, provided that the above copyright
12: * notice appear in all copies. The University of California
13: * makes no representations about the suitability of this
14: * software for any purpose. It is provided "as is" without
15: * express or implied warranty.
16: */
17:
18: #ifndef lint
19: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdAH.c,v 1.76 92/07/06 09:49:41 ouster Exp $ SPRITE (Berkeley)";
20: #endif
21:
22: #include "tclint.h"
23:
24:
25: /*
26: *----------------------------------------------------------------------
27: *
28: * Tcl_BreakCmd --
29: *
30: * This procedure is invoked to process the "break" Tcl command.
31: * See the user documentation for details on what it does.
32: *
33: * Results:
34: * A standard Tcl result.
35: *
36: * Side effects:
37: * See the user documentation.
38: *
39: *----------------------------------------------------------------------
40: */
41:
42: /* ARGSUSED */
43: int
44: Tcl_BreakCmd(dummy, interp, argc, argv)
45: ClientData dummy; /* Not used. */
46: Tcl_Interp *interp; /* Current interpreter. */
47: int argc; /* Number of arguments. */
48: char **argv; /* Argument strings. */
49: {
50: if (argc != 1) {
51: Tcl_AppendResult(interp, "wrong # args: should be \"",
52: argv[0], "\"", (char *) NULL);
53: return TCL_ERROR;
54: }
55: return TCL_BREAK;
56: }
57:
58: /*
59: *----------------------------------------------------------------------
60: *
61: * Tcl_CaseCmd --
62: *
63: * This procedure is invoked to process the "case" Tcl command.
64: * See the user documentation for details on what it does.
65: *
66: * Results:
67: * A standard Tcl result.
68: *
69: * Side effects:
70: * See the user documentation.
71: *
72: *----------------------------------------------------------------------
73: */
74:
75: /* ARGSUSED */
76: int
77: Tcl_CaseCmd(dummy, interp, argc, argv)
78: ClientData dummy; /* Not used. */
79: Tcl_Interp *interp; /* Current interpreter. */
80: int argc; /* Number of arguments. */
81: char **argv; /* Argument strings. */
82: {
83: int i, result;
84: int body;
85: char *string;
86: int caseArgc, splitArgs;
87: char **caseArgv;
88:
89: if (argc < 3) {
90: Tcl_AppendResult(interp, "wrong # args: should be \"",
91: argv[0], " string ?in? patList body ... ?default body?\"",
92: (char *) NULL);
93: return TCL_ERROR;
94: }
95: string = argv[1];
96: body = -1;
97: if (strcmp(argv[2], "in") == 0) {
98: i = 3;
99: } else {
100: i = 2;
101: }
102: caseArgc = argc - i;
103: caseArgv = argv + i;
104:
105: /*
106: * If all of the pattern/command pairs are lumped into a single
107: * argument, split them out again.
108: */
109:
110: splitArgs = 0;
111: if (caseArgc == 1) {
112: result = Tcl_SplitList(interp, caseArgv[0], &caseArgc, &caseArgv);
113: if (result != TCL_OK) {
114: return result;
115: }
116: splitArgs = 1;
117: }
118:
119: for (i = 0; i < caseArgc; i += 2) {
120: int patArgc, j;
121: char **patArgv;
122: register char *p;
123:
124: if (i == (caseArgc-1)) {
125: interp->result = "extra case pattern with no body";
126: result = TCL_ERROR;
127: goto cleanup;
128: }
129:
130: /*
131: * Check for special case of single pattern (no list) with
132: * no backslash sequences.
133: */
134:
135: for (p = caseArgv[i]; *p != 0; p++) {
136: if (isspace(*p) || (*p == '\\')) {
137: break;
138: }
139: }
140: if (*p == 0) {
141: if ((*caseArgv[i] == 'd')
142: && (strcmp(caseArgv[i], "default") == 0)) {
143: body = i+1;
144: }
145: if (Tcl_StringMatch(string, caseArgv[i])) {
146: body = i+1;
147: goto match;
148: }
149: continue;
150: }
151:
152: /*
153: * Break up pattern lists, then check each of the patterns
154: * in the list.
155: */
156:
157: result = Tcl_SplitList(interp, caseArgv[i], &patArgc, &patArgv);
158: if (result != TCL_OK) {
159: goto cleanup;
160: }
161: for (j = 0; j < patArgc; j++) {
162: if (Tcl_StringMatch(string, patArgv[j])) {
163: body = i+1;
164: break;
165: }
166: }
167: ckfree((char *) patArgv);
168: if (j < patArgc) {
169: break;
170: }
171: }
172:
173: match:
174: if (body != -1) {
175: result = Tcl_Eval(interp, caseArgv[body], 0, (char **) NULL);
176: if (result == TCL_ERROR) {
177: char msg[100];
178: sprintf(msg, "\n (\"%.50s\" arm line %d)", caseArgv[body-1],
179: interp->errorLine);
180: Tcl_AddErrorInfo(interp, msg);
181: }
182: goto cleanup;
183: }
184:
185: /*
186: * Nothing matched: return nothing.
187: */
188:
189: result = TCL_OK;
190:
191: cleanup:
192: if (splitArgs) {
193: ckfree((char *) caseArgv);
194: }
195: return result;
196: }
197:
198: /*
199: *----------------------------------------------------------------------
200: *
201: * Tcl_CatchCmd --
202: *
203: * This procedure is invoked to process the "catch" Tcl command.
204: * See the user documentation for details on what it does.
205: *
206: * Results:
207: * A standard Tcl result.
208: *
209: * Side effects:
210: * See the user documentation.
211: *
212: *----------------------------------------------------------------------
213: */
214:
215: /* ARGSUSED */
216: int
217: Tcl_CatchCmd(dummy, interp, argc, argv)
218: ClientData dummy; /* Not used. */
219: Tcl_Interp *interp; /* Current interpreter. */
220: int argc; /* Number of arguments. */
221: char **argv; /* Argument strings. */
222: {
223: int result;
224:
225: if ((argc != 2) && (argc != 3)) {
226: Tcl_AppendResult(interp, "wrong # args: should be \"",
227: argv[0], " command ?varName?\"", (char *) NULL);
228: return TCL_ERROR;
229: }
230: result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
231: if (argc == 3) {
232: if (Tcl_SetVar(interp, argv[2], interp->result, 0) == NULL) {
233: Tcl_SetResult(interp, "couldn't save command result in variable",
234: TCL_STATIC);
235: return TCL_ERROR;
236: }
237: }
238: Tcl_ResetResult(interp);
239: sprintf(interp->result, "%d", result);
240: return TCL_OK;
241: }
242:
243: /*
244: *----------------------------------------------------------------------
245: *
246: * Tcl_ConcatCmd --
247: *
248: * This procedure is invoked to process the "concat" Tcl command.
249: * See the user documentation for details on what it does.
250: *
251: * Results:
252: * A standard Tcl result.
253: *
254: * Side effects:
255: * See the user documentation.
256: *
257: *----------------------------------------------------------------------
258: */
259:
260: /* ARGSUSED */
261: int
262: Tcl_ConcatCmd(dummy, interp, argc, argv)
263: ClientData dummy; /* Not used. */
264: Tcl_Interp *interp; /* Current interpreter. */
265: int argc; /* Number of arguments. */
266: char **argv; /* Argument strings. */
267: {
268: if (argc == 1) {
269: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
270: " arg ?arg ...?\"", (char *) NULL);
271: return TCL_ERROR;
272: }
273:
274: interp->result = Tcl_Concat(argc-1, argv+1);
275: interp->freeProc = (Tcl_FreeProc *) free;
276: return TCL_OK;
277: }
278:
279: /*
280: *----------------------------------------------------------------------
281: *
282: * Tcl_ContinueCmd --
283: *
284: * This procedure is invoked to process the "continue" Tcl command.
285: * See the user documentation for details on what it does.
286: *
287: * Results:
288: * A standard Tcl result.
289: *
290: * Side effects:
291: * See the user documentation.
292: *
293: *----------------------------------------------------------------------
294: */
295:
296: /* ARGSUSED */
297: int
298: Tcl_ContinueCmd(dummy, interp, argc, argv)
299: ClientData dummy; /* Not used. */
300: Tcl_Interp *interp; /* Current interpreter. */
301: int argc; /* Number of arguments. */
302: char **argv; /* Argument strings. */
303: {
304: if (argc != 1) {
305: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
306: "\"", (char *) NULL);
307: return TCL_ERROR;
308: }
309: return TCL_CONTINUE;
310: }
311:
312: /*
313: *----------------------------------------------------------------------
314: *
315: * Tcl_ErrorCmd --
316: *
317: * This procedure is invoked to process the "error" Tcl command.
318: * See the user documentation for details on what it does.
319: *
320: * Results:
321: * A standard Tcl result.
322: *
323: * Side effects:
324: * See the user documentation.
325: *
326: *----------------------------------------------------------------------
327: */
328:
329: /* ARGSUSED */
330: int
331: Tcl_ErrorCmd(dummy, interp, argc, argv)
332: ClientData dummy; /* Not used. */
333: Tcl_Interp *interp; /* Current interpreter. */
334: int argc; /* Number of arguments. */
335: char **argv; /* Argument strings. */
336: {
337: Interp *iPtr = (Interp *) interp;
338:
339: if ((argc < 2) || (argc > 4)) {
340: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
341: " message ?errorInfo? ?errorCode?\"", (char *) NULL);
342: return TCL_ERROR;
343: }
344: if ((argc >= 3) && (argv[2][0] != 0)) {
345: Tcl_AddErrorInfo(interp, argv[2]);
346: iPtr->flags |= ERR_ALREADY_LOGGED;
347: }
348: if (argc == 4) {
349: Tcl_SetVar2(interp, "errorCode", (char *) NULL, argv[3],
350: TCL_GLOBAL_ONLY);
351: iPtr->flags |= ERROR_CODE_SET;
352: }
353: Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
354: return TCL_ERROR;
355: }
356:
357: /*
358: *----------------------------------------------------------------------
359: *
360: * Tcl_EvalCmd --
361: *
362: * This procedure is invoked to process the "eval" Tcl command.
363: * See the user documentation for details on what it does.
364: *
365: * Results:
366: * A standard Tcl result.
367: *
368: * Side effects:
369: * See the user documentation.
370: *
371: *----------------------------------------------------------------------
372: */
373:
374: /* ARGSUSED */
375: int
376: Tcl_EvalCmd(dummy, interp, argc, argv)
377: ClientData dummy; /* Not used. */
378: Tcl_Interp *interp; /* Current interpreter. */
379: int argc; /* Number of arguments. */
380: char **argv; /* Argument strings. */
381: {
382: int result;
383: char *cmd;
384:
385: if (argc < 2) {
386: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
387: " arg ?arg ...?\"", (char *) NULL);
388: return TCL_ERROR;
389: }
390: if (argc == 2) {
391: result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
392: } else {
393:
394: /*
395: * More than one argument: concatenate them together with spaces
396: * between, then evaluate the result.
397: */
398:
399: cmd = Tcl_Concat(argc-1, argv+1);
400: result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
401: ckfree(cmd);
402: }
403: if (result == TCL_ERROR) {
404: char msg[60];
405: sprintf(msg, "\n (\"eval\" body line %d)", interp->errorLine);
406: Tcl_AddErrorInfo(interp, msg);
407: }
408: return result;
409: }
410:
411: /*
412: *----------------------------------------------------------------------
413: *
414: * Tcl_ExprCmd --
415: *
416: * This procedure is invoked to process the "expr" Tcl command.
417: * See the user documentation for details on what it does.
418: *
419: * Results:
420: * A standard Tcl result.
421: *
422: * Side effects:
423: * See the user documentation.
424: *
425: *----------------------------------------------------------------------
426: */
427:
428: /* ARGSUSED */
429: int
430: Tcl_ExprCmd(dummy, interp, argc, argv)
431: ClientData dummy; /* Not used. */
432: Tcl_Interp *interp; /* Current interpreter. */
433: int argc; /* Number of arguments. */
434: char **argv; /* Argument strings. */
435: {
436: if (argc != 2) {
437: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
438: " expression\"", (char *) NULL);
439: return TCL_ERROR;
440: }
441:
442: return Tcl_ExprString(interp, argv[1]);
443: }
444:
445: /*
446: *----------------------------------------------------------------------
447: *
448: * Tcl_ForCmd --
449: *
450: * This procedure is invoked to process the "for" Tcl command.
451: * See the user documentation for details on what it does.
452: *
453: * Results:
454: * A standard Tcl result.
455: *
456: * Side effects:
457: * See the user documentation.
458: *
459: *----------------------------------------------------------------------
460: */
461:
462: /* ARGSUSED */
463: int
464: Tcl_ForCmd(dummy, interp, argc, argv)
465: ClientData dummy; /* Not used. */
466: Tcl_Interp *interp; /* Current interpreter. */
467: int argc; /* Number of arguments. */
468: char **argv; /* Argument strings. */
469: {
470: int result, value;
471:
472: if (argc != 5) {
473: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
474: " start test next command\"", (char *) NULL);
475: return TCL_ERROR;
476: }
477:
478: result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
479: if (result != TCL_OK) {
480: if (result == TCL_ERROR) {
481: Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)");
482: }
483: return result;
484: }
485: while (1) {
486: result = Tcl_ExprBoolean(interp, argv[2], &value);
487: if (result != TCL_OK) {
488: return result;
489: }
490: if (!value) {
491: break;
492: }
493: result = Tcl_Eval(interp, argv[4], 0, (char **) NULL);
494: if (result == TCL_CONTINUE) {
495: result = TCL_OK;
496: } else if (result != TCL_OK) {
497: if (result == TCL_ERROR) {
498: char msg[60];
499: sprintf(msg, "\n (\"for\" body line %d)", interp->errorLine);
500: Tcl_AddErrorInfo(interp, msg);
501: }
502: break;
503: }
504: result = Tcl_Eval(interp, argv[3], 0, (char **) NULL);
505: if (result == TCL_BREAK) {
506: break;
507: } else if (result != TCL_OK) {
508: if (result == TCL_ERROR) {
509: Tcl_AddErrorInfo(interp, "\n (\"for\" loop-end command)");
510: }
511: return result;
512: }
513: }
514: if (result == TCL_BREAK) {
515: result = TCL_OK;
516: }
517: if (result == TCL_OK) {
518: Tcl_ResetResult(interp);
519: }
520: return result;
521: }
522:
523: /*
524: *----------------------------------------------------------------------
525: *
526: * Tcl_ForeachCmd --
527: *
528: * This procedure is invoked to process the "foreach" Tcl command.
529: * See the user documentation for details on what it does.
530: *
531: * Results:
532: * A standard Tcl result.
533: *
534: * Side effects:
535: * See the user documentation.
536: *
537: *----------------------------------------------------------------------
538: */
539:
540: /* ARGSUSED */
541: int
542: Tcl_ForeachCmd(dummy, interp, argc, argv)
543: ClientData dummy; /* Not used. */
544: Tcl_Interp *interp; /* Current interpreter. */
545: int argc; /* Number of arguments. */
546: char **argv; /* Argument strings. */
547: {
548: int listArgc, i, result;
549: char **listArgv;
550:
551: if (argc != 4) {
552: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
553: " varName list command\"", (char *) NULL);
554: return TCL_ERROR;
555: }
556:
557: /*
558: * Break the list up into elements, and execute the command once
559: * for each value of the element.
560: */
561:
562: result = Tcl_SplitList(interp, argv[2], &listArgc, &listArgv);
563: if (result != TCL_OK) {
564: return result;
565: }
566: for (i = 0; i < listArgc; i++) {
567: if (Tcl_SetVar(interp, argv[1], listArgv[i], 0) == NULL) {
568: Tcl_SetResult(interp, "couldn't set loop variable", TCL_STATIC);
569: result = TCL_ERROR;
570: break;
571: }
572:
573: result = Tcl_Eval(interp, argv[3], 0, (char **) NULL);
574: if (result != TCL_OK) {
575: if (result == TCL_CONTINUE) {
576: result = TCL_OK;
577: } else if (result == TCL_BREAK) {
578: result = TCL_OK;
579: break;
580: } else if (result == TCL_ERROR) {
581: char msg[100];
582: sprintf(msg, "\n (\"foreach\" body line %d)",
583: interp->errorLine);
584: Tcl_AddErrorInfo(interp, msg);
585: break;
586: } else {
587: break;
588: }
589: }
590: }
591: ckfree((char *) listArgv);
592: if (result == TCL_OK) {
593: Tcl_ResetResult(interp);
594: }
595: return result;
596: }
597:
598: /*
599: *----------------------------------------------------------------------
600: *
601: * Tcl_FormatCmd --
602: *
603: * This procedure is invoked to process the "format" Tcl command.
604: * See the user documentation for details on what it does.
605: *
606: * Results:
607: * A standard Tcl result.
608: *
609: * Side effects:
610: * See the user documentation.
611: *
612: *----------------------------------------------------------------------
613: */
614:
615: /* ARGSUSED */
616: int
617: Tcl_FormatCmd(dummy, interp, argc, argv)
618: ClientData dummy; /* Not used. */
619: Tcl_Interp *interp; /* Current interpreter. */
620: int argc; /* Number of arguments. */
621: char **argv; /* Argument strings. */
622: {
623: register char *format; /* Used to read characters from the format
624: * string. */
625: char newFormat[40]; /* A new format specifier is generated here. */
626: int width; /* Field width from field specifier, or 0 if
627: * no width given. */
628: int precision; /* Field precision from field specifier, or 0
629: * if no precision given. */
630: int size; /* Number of bytes needed for result of
631: * conversion, based on type of conversion
632: * ("e", "s", etc.) and width from above. */
633: char *oneWordValue = NULL; /* Used to hold value to pass to sprintf, if
634: * it's a one-word value. */
635: double twoWordValue; /* Used to hold value to pass to sprintf if
636: * it's a two-word value. */
637: int useTwoWords; /* 0 means use oneWordValue, 1 means use
638: * twoWordValue. */
639: char *dst = interp->result; /* Where result is stored. Starts off at
640: * interp->resultSpace, but may get dynamically
641: * re-allocated if this isn't enough. */
642: int dstSize = 0; /* Number of non-null characters currently
643: * stored at dst. */
644: int dstSpace = TCL_RESULT_SIZE;
645: /* Total amount of storage space available
646: * in dst (not including null terminator. */
647: int noPercent; /* Special case for speed: indicates there's
648: * no field specifier, just a string to copy. */
649: char **curArg; /* Remainder of argv array. */
650: int useShort; /* Value to be printed is short (half word). */
651:
652: /*
653: * This procedure is a bit nasty. The goal is to use sprintf to
654: * do most of the dirty work. There are several problems:
655: * 1. this procedure can't trust its arguments.
656: * 2. we must be able to provide a large enough result area to hold
657: * whatever's generated. This is hard to estimate.
658: * 2. there's no way to move the arguments from argv to the call
659: * to sprintf in a reasonable way. This is particularly nasty
660: * because some of the arguments may be two-word values (doubles).
661: * So, what happens here is to scan the format string one % group
662: * at a time, making many individual calls to sprintf.
663: */
664:
665: if (argc < 2) {
666: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
667: " formatString ?arg arg ...?\"", (char *) NULL);
668: return TCL_ERROR;
669: }
670: curArg = argv+2;
671: argc -= 2;
672: for (format = argv[1]; *format != 0; ) {
673: register char *newPtr = newFormat;
674:
675: width = precision = useTwoWords = noPercent = useShort = 0;
676:
677: /*
678: * Get rid of any characters before the next field specifier.
679: * Collapse backslash sequences found along the way.
680: */
681:
682: if (*format != '%') {
683: register char *p;
684: int bsSize;
685:
686: oneWordValue = p = format;
687: while ((*format != '%') && (*format != 0)) {
688: if (*format == '\\') {
689: *p = Tcl_Backslash(format, &bsSize);
690: if (*p != 0) {
691: p++;
692: }
693: format += bsSize;
694: } else {
695: *p = *format;
696: p++;
697: format++;
698: }
699: }
700: size = p - oneWordValue;
701: noPercent = 1;
702: goto doField;
703: }
704:
705: if (format[1] == '%') {
706: oneWordValue = format;
707: size = 1;
708: noPercent = 1;
709: format += 2;
710: goto doField;
711: }
712:
713: /*
714: * Parse off a field specifier, compute how many characters
715: * will be needed to store the result, and substitute for
716: * "*" size specifiers.
717: */
718:
719: *newPtr = '%';
720: newPtr++;
721: format++;
722: while ((*format == '-') || (*format == '#')) {
723: *newPtr = *format;
724: newPtr++;
725: format++;
726: }
727: if (*format == '0') {
728: *newPtr = '0';
729: newPtr++;
730: format++;
731: }
732: if (isdigit(*format)) {
733: width = atoi(format);
734: do {
735: format++;
736: } while (isdigit(*format));
737: } else if (*format == '*') {
738: if (argc <= 0) {
739: goto notEnoughArgs;
740: }
741: if (Tcl_GetInt(interp, *curArg, &width) != TCL_OK) {
742: goto fmtError;
743: }
744: argc--;
745: curArg++;
746: format++;
747: }
748: if (width != 0) {
749: sprintf(newPtr, "%d", width);
750: while (*newPtr != 0) {
751: newPtr++;
752: }
753: }
754: if (*format == '.') {
755: *newPtr = '.';
756: newPtr++;
757: format++;
758: }
759: if (isdigit(*format)) {
760: precision = atoi(format);
761: do {
762: format++;
763: } while (isdigit(*format));
764: } else if (*format == '*') {
765: if (argc <= 0) {
766: goto notEnoughArgs;
767: }
768: if (Tcl_GetInt(interp, *curArg, &precision) != TCL_OK) {
769: goto fmtError;
770: }
771: argc--;
772: curArg++;
773: format++;
774: }
775: if (precision != 0) {
776: sprintf(newPtr, "%d", precision);
777: while (*newPtr != 0) {
778: newPtr++;
779: }
780: }
781: if (*format == 'l') {
782: format++;
783: } else if (*format == 'h') {
784: useShort = 1;
785: *newPtr = 'h';
786: newPtr++;
787: format++;
788: }
789: *newPtr = *format;
790: newPtr++;
791: *newPtr = 0;
792: if (argc <= 0) {
793: goto notEnoughArgs;
794: }
795: switch (*format) {
796: case 'D':
797: case 'O':
798: case 'U':
799: if (!useShort) {
800: newPtr++;
801: } else {
802: useShort = 0;
803: }
804: newPtr[-1] = tolower(*format);
805: newPtr[-2] = 'l';
806: *newPtr = 0;
807: case 'd':
808: case 'o':
809: case 'u':
810: case 'x':
811: case 'X':
812: if (Tcl_GetInt(interp, *curArg, (int *) &oneWordValue)
813: != TCL_OK) {
814: goto fmtError;
815: }
816: size = 40;
817: break;
818: case 's':
819: oneWordValue = *curArg;
820: size = strlen(*curArg);
821: break;
822: case 'c':
823: if (Tcl_GetInt(interp, *curArg, (int *) &oneWordValue)
824: != TCL_OK) {
825: goto fmtError;
826: }
827: size = 1;
828: break;
829: case 'F':
830: newPtr[-1] = tolower(newPtr[-1]);
831: case 'e':
832: case 'E':
833: case 'f':
834: case 'g':
835: case 'G':
836: if (Tcl_GetDouble(interp, *curArg, &twoWordValue) != TCL_OK) {
837: goto fmtError;
838: }
839: useTwoWords = 1;
840: size = 320;
841: if (precision > 10) {
842: size += precision;
843: }
844: break;
845: case 0:
846: interp->result =
847: "format string ended in middle of field specifier";
848: goto fmtError;
849: default:
850: sprintf(interp->result, "bad field specifier \"%c\"", *format);
851: goto fmtError;
852: }
853: argc--;
854: curArg++;
855: format++;
856:
857: /*
858: * Make sure that there's enough space to hold the formatted
859: * result, then format it.
860: */
861:
862: doField:
863: if (width > size) {
864: size = width;
865: }
866: if ((dstSize + size) > dstSpace) {
867: char *newDst;
868: int newSpace;
869:
870: newSpace = 2*(dstSize + size);
871: newDst = (char *) ckalloc((unsigned) newSpace+1);
872: if (dstSize != 0) {
873: memcpy((VOID *) newDst, (VOID *) dst, dstSize);
874: }
875: if (dstSpace != TCL_RESULT_SIZE) {
876: ckfree(dst);
877: }
878: dst = newDst;
879: dstSpace = newSpace;
880: }
881: if (noPercent) {
882: memcpy((VOID *) (dst+dstSize), (VOID *) oneWordValue, size);
883: dstSize += size;
884: dst[dstSize] = 0;
885: } else {
886: if (useTwoWords) {
887: sprintf(dst+dstSize, newFormat, twoWordValue);
888: } else if (useShort) {
889: int tmp = (int)oneWordValue;
890: sprintf(dst+dstSize, newFormat, (short)tmp);
891: } else {
892: sprintf(dst+dstSize, newFormat, oneWordValue);
893: }
894: dstSize += strlen(dst+dstSize);
895: }
896: }
897:
898: interp->result = dst;
899: if (dstSpace != TCL_RESULT_SIZE) {
900: interp->freeProc = (Tcl_FreeProc *) free;
901: } else {
902: interp->freeProc = 0;
903: }
904: return TCL_OK;
905:
906: notEnoughArgs:
907: interp->result = "not enough arguments for all format specifiers";
908: fmtError:
909: if (dstSpace != TCL_RESULT_SIZE) {
910: ckfree(dst);
911: }
912: return TCL_ERROR;
913: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.