]>
cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclcmdah.c
d1bf65fc868ca9322c4254141ff07ab6f46422bd
4 * This file contains the top-level command routines for most of
5 * the Tcl built-in commands whose names begin with the letters
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.
19 static char rcsid
[] = "$Header: /user6/ouster/tcl/RCS/tclCmdAH.c,v 1.76 92/07/06 09:49:41 ouster Exp $ SPRITE (Berkeley)";
26 *----------------------------------------------------------------------
30 * This procedure is invoked to process the "break" Tcl command.
31 * See the user documentation for details on what it does.
34 * A standard Tcl result.
37 * See the user documentation.
39 *----------------------------------------------------------------------
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. */
51 Tcl_AppendResult(interp
, "wrong # args: should be \"",
52 argv
[0], "\"", (char *) NULL
);
59 *----------------------------------------------------------------------
63 * This procedure is invoked to process the "case" Tcl command.
64 * See the user documentation for details on what it does.
67 * A standard Tcl result.
70 * See the user documentation.
72 *----------------------------------------------------------------------
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. */
86 int caseArgc
, splitArgs
;
90 Tcl_AppendResult(interp
, "wrong # args: should be \"",
91 argv
[0], " string ?in? patList body ... ?default body?\"",
97 if (strcmp(argv
[2], "in") == 0) {
106 * If all of the pattern/command pairs are lumped into a single
107 * argument, split them out again.
112 result
= Tcl_SplitList(interp
, caseArgv
[0], &caseArgc
, &caseArgv
);
113 if (result
!= TCL_OK
) {
119 for (i
= 0; i
< caseArgc
; i
+= 2) {
124 if (i
== (caseArgc
-1)) {
125 interp
->result
= "extra case pattern with no body";
131 * Check for special case of single pattern (no list) with
132 * no backslash sequences.
135 for (p
= caseArgv
[i
]; *p
!= 0; p
++) {
136 if (isspace(*p
) || (*p
== '\\')) {
141 if ((*caseArgv
[i
] == 'd')
142 && (strcmp(caseArgv
[i
], "default") == 0)) {
145 if (Tcl_StringMatch(string
, caseArgv
[i
])) {
153 * Break up pattern lists, then check each of the patterns
157 result
= Tcl_SplitList(interp
, caseArgv
[i
], &patArgc
, &patArgv
);
158 if (result
!= TCL_OK
) {
161 for (j
= 0; j
< patArgc
; j
++) {
162 if (Tcl_StringMatch(string
, patArgv
[j
])) {
167 ckfree((char *) patArgv
);
175 result
= Tcl_Eval(interp
, caseArgv
[body
], 0, (char **) NULL
);
176 if (result
== TCL_ERROR
) {
178 sprintf(msg
, "\n (\"%.50s\" arm line %d)", caseArgv
[body
-1],
180 Tcl_AddErrorInfo(interp
, msg
);
186 * Nothing matched: return nothing.
193 ckfree((char *) caseArgv
);
199 *----------------------------------------------------------------------
203 * This procedure is invoked to process the "catch" Tcl command.
204 * See the user documentation for details on what it does.
207 * A standard Tcl result.
210 * See the user documentation.
212 *----------------------------------------------------------------------
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. */
225 if ((argc
!= 2) && (argc
!= 3)) {
226 Tcl_AppendResult(interp
, "wrong # args: should be \"",
227 argv
[0], " command ?varName?\"", (char *) NULL
);
230 result
= Tcl_Eval(interp
, argv
[1], 0, (char **) NULL
);
232 if (Tcl_SetVar(interp
, argv
[2], interp
->result
, 0) == NULL
) {
233 Tcl_SetResult(interp
, "couldn't save command result in variable",
238 Tcl_ResetResult(interp
);
239 sprintf(interp
->result
, "%d", result
);
244 *----------------------------------------------------------------------
248 * This procedure is invoked to process the "concat" Tcl command.
249 * See the user documentation for details on what it does.
252 * A standard Tcl result.
255 * See the user documentation.
257 *----------------------------------------------------------------------
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. */
269 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
270 " arg ?arg ...?\"", (char *) NULL
);
274 interp
->result
= Tcl_Concat(argc
-1, argv
+1);
275 interp
->freeProc
= (Tcl_FreeProc
*) free
;
280 *----------------------------------------------------------------------
284 * This procedure is invoked to process the "continue" Tcl command.
285 * See the user documentation for details on what it does.
288 * A standard Tcl result.
291 * See the user documentation.
293 *----------------------------------------------------------------------
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. */
305 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
306 "\"", (char *) NULL
);
313 *----------------------------------------------------------------------
317 * This procedure is invoked to process the "error" Tcl command.
318 * See the user documentation for details on what it does.
321 * A standard Tcl result.
324 * See the user documentation.
326 *----------------------------------------------------------------------
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. */
337 Interp
*iPtr
= (Interp
*) interp
;
339 if ((argc
< 2) || (argc
> 4)) {
340 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
341 " message ?errorInfo? ?errorCode?\"", (char *) NULL
);
344 if ((argc
>= 3) && (argv
[2][0] != 0)) {
345 Tcl_AddErrorInfo(interp
, argv
[2]);
346 iPtr
->flags
|= ERR_ALREADY_LOGGED
;
349 Tcl_SetVar2(interp
, "errorCode", (char *) NULL
, argv
[3],
351 iPtr
->flags
|= ERROR_CODE_SET
;
353 Tcl_SetResult(interp
, argv
[1], TCL_VOLATILE
);
358 *----------------------------------------------------------------------
362 * This procedure is invoked to process the "eval" Tcl command.
363 * See the user documentation for details on what it does.
366 * A standard Tcl result.
369 * See the user documentation.
371 *----------------------------------------------------------------------
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. */
386 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
387 " arg ?arg ...?\"", (char *) NULL
);
391 result
= Tcl_Eval(interp
, argv
[1], 0, (char **) NULL
);
395 * More than one argument: concatenate them together with spaces
396 * between, then evaluate the result.
399 cmd
= Tcl_Concat(argc
-1, argv
+1);
400 result
= Tcl_Eval(interp
, cmd
, 0, (char **) NULL
);
403 if (result
== TCL_ERROR
) {
405 sprintf(msg
, "\n (\"eval\" body line %d)", interp
->errorLine
);
406 Tcl_AddErrorInfo(interp
, msg
);
412 *----------------------------------------------------------------------
416 * This procedure is invoked to process the "expr" Tcl command.
417 * See the user documentation for details on what it does.
420 * A standard Tcl result.
423 * See the user documentation.
425 *----------------------------------------------------------------------
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. */
437 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
438 " expression\"", (char *) NULL
);
442 return Tcl_ExprString(interp
, argv
[1]);
446 *----------------------------------------------------------------------
450 * This procedure is invoked to process the "for" Tcl command.
451 * See the user documentation for details on what it does.
454 * A standard Tcl result.
457 * See the user documentation.
459 *----------------------------------------------------------------------
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. */
473 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
474 " start test next command\"", (char *) NULL
);
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)");
486 result
= Tcl_ExprBoolean(interp
, argv
[2], &value
);
487 if (result
!= TCL_OK
) {
493 result
= Tcl_Eval(interp
, argv
[4], 0, (char **) NULL
);
494 if (result
== TCL_CONTINUE
) {
496 } else if (result
!= TCL_OK
) {
497 if (result
== TCL_ERROR
) {
499 sprintf(msg
, "\n (\"for\" body line %d)", interp
->errorLine
);
500 Tcl_AddErrorInfo(interp
, msg
);
504 result
= Tcl_Eval(interp
, argv
[3], 0, (char **) NULL
);
505 if (result
== TCL_BREAK
) {
507 } else if (result
!= TCL_OK
) {
508 if (result
== TCL_ERROR
) {
509 Tcl_AddErrorInfo(interp
, "\n (\"for\" loop-end command)");
514 if (result
== TCL_BREAK
) {
517 if (result
== TCL_OK
) {
518 Tcl_ResetResult(interp
);
524 *----------------------------------------------------------------------
528 * This procedure is invoked to process the "foreach" Tcl command.
529 * See the user documentation for details on what it does.
532 * A standard Tcl result.
535 * See the user documentation.
537 *----------------------------------------------------------------------
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. */
548 int listArgc
, i
, result
;
552 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
553 " varName list command\"", (char *) NULL
);
558 * Break the list up into elements, and execute the command once
559 * for each value of the element.
562 result
= Tcl_SplitList(interp
, argv
[2], &listArgc
, &listArgv
);
563 if (result
!= TCL_OK
) {
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
);
573 result
= Tcl_Eval(interp
, argv
[3], 0, (char **) NULL
);
574 if (result
!= TCL_OK
) {
575 if (result
== TCL_CONTINUE
) {
577 } else if (result
== TCL_BREAK
) {
580 } else if (result
== TCL_ERROR
) {
582 sprintf(msg
, "\n (\"foreach\" body line %d)",
584 Tcl_AddErrorInfo(interp
, msg
);
591 ckfree((char *) listArgv
);
592 if (result
== TCL_OK
) {
593 Tcl_ResetResult(interp
);
599 *----------------------------------------------------------------------
603 * This procedure is invoked to process the "format" Tcl command.
604 * See the user documentation for details on what it does.
607 * A standard Tcl result.
610 * See the user documentation.
612 *----------------------------------------------------------------------
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. */
623 register char *format
; /* Used to read characters from the format
625 char newFormat
[40]; /* A new format specifier is generated here. */
626 int width
; /* Field width from field specifier, or 0 if
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
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
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). */
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.
666 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
667 " formatString ?arg arg ...?\"", (char *) NULL
);
672 for (format
= argv
[1]; *format
!= 0; ) {
673 register char *newPtr
= newFormat
;
675 width
= precision
= useTwoWords
= noPercent
= useShort
= 0;
678 * Get rid of any characters before the next field specifier.
679 * Collapse backslash sequences found along the way.
682 if (*format
!= '%') {
686 oneWordValue
= p
= format
;
687 while ((*format
!= '%') && (*format
!= 0)) {
688 if (*format
== '\\') {
689 *p
= Tcl_Backslash(format
, &bsSize
);
700 size
= p
- oneWordValue
;
705 if (format
[1] == '%') {
706 oneWordValue
= format
;
714 * Parse off a field specifier, compute how many characters
715 * will be needed to store the result, and substitute for
716 * "*" size specifiers.
722 while ((*format
== '-') || (*format
== '#')) {
727 if (*format
== '0') {
732 if (isdigit(*format
)) {
733 width
= atoi(format
);
736 } while (isdigit(*format
));
737 } else if (*format
== '*') {
741 if (Tcl_GetInt(interp
, *curArg
, &width
) != TCL_OK
) {
749 sprintf(newPtr
, "%d", width
);
750 while (*newPtr
!= 0) {
754 if (*format
== '.') {
759 if (isdigit(*format
)) {
760 precision
= atoi(format
);
763 } while (isdigit(*format
));
764 } else if (*format
== '*') {
768 if (Tcl_GetInt(interp
, *curArg
, &precision
) != TCL_OK
) {
775 if (precision
!= 0) {
776 sprintf(newPtr
, "%d", precision
);
777 while (*newPtr
!= 0) {
781 if (*format
== 'l') {
783 } else if (*format
== 'h') {
804 newPtr
[-1] = tolower(*format
);
812 if (Tcl_GetInt(interp
, *curArg
, (int *) &oneWordValue
)
819 oneWordValue
= *curArg
;
820 size
= strlen(*curArg
);
823 if (Tcl_GetInt(interp
, *curArg
, (int *) &oneWordValue
)
830 newPtr
[-1] = tolower(newPtr
[-1]);
836 if (Tcl_GetDouble(interp
, *curArg
, &twoWordValue
) != TCL_OK
) {
841 if (precision
> 10) {
847 "format string ended in middle of field specifier";
850 sprintf(interp
->result
, "bad field specifier \"%c\"", *format
);
858 * Make sure that there's enough space to hold the formatted
859 * result, then format it.
866 if ((dstSize
+ size
) > dstSpace
) {
870 newSpace
= 2*(dstSize
+ size
);
871 newDst
= (char *) ckalloc((unsigned) newSpace
+1);
873 memcpy((VOID
*) newDst
, (VOID
*) dst
, dstSize
);
875 if (dstSpace
!= TCL_RESULT_SIZE
) {
882 memcpy((VOID
*) (dst
+dstSize
), (VOID
*) oneWordValue
, size
);
887 sprintf(dst
+dstSize
, newFormat
, twoWordValue
);
888 } else if (useShort
) {
889 int tmp
= (int)oneWordValue
;
890 sprintf(dst
+dstSize
, newFormat
, (short)tmp
);
892 sprintf(dst
+dstSize
, newFormat
, oneWordValue
);
894 dstSize
+= strlen(dst
+dstSize
);
898 interp
->result
= dst
;
899 if (dstSpace
!= TCL_RESULT_SIZE
) {
900 interp
->freeProc
= (Tcl_FreeProc
*) free
;
902 interp
->freeProc
= 0;
907 interp
->result
= "not enough arguments for all format specifiers";
909 if (dstSpace
!= TCL_RESULT_SIZE
) {