]>
cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclcmdah.c
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 *----------------------------------------------------------------------
45 ClientData dummy
, /* Not used. */
46 Tcl_Interp
*interp
, /* Current interpreter. */
47 int argc
, /* Number of arguments. */
48 char **argv
/* Argument strings. */
52 Tcl_AppendResult(interp
, "wrong # args: should be \"",
53 argv
[0], "\"", (char *) NULL
);
60 *----------------------------------------------------------------------
64 * This procedure is invoked to process the "case" Tcl command.
65 * See the user documentation for details on what it does.
68 * A standard Tcl result.
71 * See the user documentation.
73 *----------------------------------------------------------------------
79 ClientData dummy
, /* Not used. */
80 Tcl_Interp
*interp
, /* Current interpreter. */
81 int argc
, /* Number of arguments. */
82 char **argv
/* Argument strings. */
88 int caseArgc
, splitArgs
;
92 Tcl_AppendResult(interp
, "wrong # args: should be \"",
93 argv
[0], " string ?in? patList body ... ?default body?\"",
99 if (strcmp(argv
[2], "in") == 0) {
108 * If all of the pattern/command pairs are lumped into a single
109 * argument, split them out again.
114 result
= Tcl_SplitList(interp
, caseArgv
[0], &caseArgc
, &caseArgv
);
115 if (result
!= TCL_OK
) {
121 for (i
= 0; i
< caseArgc
; i
+= 2) {
126 if (i
== (caseArgc
-1)) {
127 interp
->result
= "extra case pattern with no body";
133 * Check for special case of single pattern (no list) with
134 * no backslash sequences.
137 for (p
= caseArgv
[i
]; *p
!= 0; p
++) {
138 if (isspace(*p
) || (*p
== '\\')) {
143 if ((*caseArgv
[i
] == 'd')
144 && (strcmp(caseArgv
[i
], "default") == 0)) {
147 if (Tcl_StringMatch(string
, caseArgv
[i
])) {
155 * Break up pattern lists, then check each of the patterns
159 result
= Tcl_SplitList(interp
, caseArgv
[i
], &patArgc
, &patArgv
);
160 if (result
!= TCL_OK
) {
163 for (j
= 0; j
< patArgc
; j
++) {
164 if (Tcl_StringMatch(string
, patArgv
[j
])) {
169 ckfree((char *) patArgv
);
177 result
= Tcl_Eval(interp
, caseArgv
[body
], 0, (char **) NULL
);
178 if (result
== TCL_ERROR
) {
180 sprintf(msg
, "\n (\"%.50s\" arm line %d)", caseArgv
[body
-1],
182 Tcl_AddErrorInfo(interp
, msg
);
188 * Nothing matched: return nothing.
195 ckfree((char *) caseArgv
);
201 *----------------------------------------------------------------------
205 * This procedure is invoked to process the "catch" Tcl command.
206 * See the user documentation for details on what it does.
209 * A standard Tcl result.
212 * See the user documentation.
214 *----------------------------------------------------------------------
220 ClientData dummy
, /* Not used. */
221 Tcl_Interp
*interp
, /* Current interpreter. */
222 int argc
, /* Number of arguments. */
223 char **argv
/* Argument strings. */
228 if ((argc
!= 2) && (argc
!= 3)) {
229 Tcl_AppendResult(interp
, "wrong # args: should be \"",
230 argv
[0], " command ?varName?\"", (char *) NULL
);
233 result
= Tcl_Eval(interp
, argv
[1], 0, (char **) NULL
);
235 if (Tcl_SetVar(interp
, argv
[2], interp
->result
, 0) == NULL
) {
236 Tcl_SetResult(interp
, "couldn't save command result in variable",
241 Tcl_ResetResult(interp
);
242 sprintf(interp
->result
, "%d", result
);
247 *----------------------------------------------------------------------
251 * This procedure is invoked to process the "concat" Tcl command.
252 * See the user documentation for details on what it does.
255 * A standard Tcl result.
258 * See the user documentation.
260 *----------------------------------------------------------------------
266 ClientData dummy
, /* Not used. */
267 Tcl_Interp
*interp
, /* Current interpreter. */
268 int argc
, /* Number of arguments. */
269 char **argv
/* Argument strings. */
273 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
274 " arg ?arg ...?\"", (char *) NULL
);
278 interp
->result
= Tcl_Concat(argc
-1, argv
+1);
279 interp
->freeProc
= (Tcl_FreeProc
*) free
;
284 *----------------------------------------------------------------------
288 * This procedure is invoked to process the "continue" Tcl command.
289 * See the user documentation for details on what it does.
292 * A standard Tcl result.
295 * See the user documentation.
297 *----------------------------------------------------------------------
303 ClientData dummy
, /* Not used. */
304 Tcl_Interp
*interp
, /* Current interpreter. */
305 int argc
, /* Number of arguments. */
306 char **argv
/* Argument strings. */
310 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
311 "\"", (char *) NULL
);
318 *----------------------------------------------------------------------
322 * This procedure is invoked to process the "error" Tcl command.
323 * See the user documentation for details on what it does.
326 * A standard Tcl result.
329 * See the user documentation.
331 *----------------------------------------------------------------------
337 ClientData dummy
, /* Not used. */
338 Tcl_Interp
*interp
, /* Current interpreter. */
339 int argc
, /* Number of arguments. */
340 char **argv
/* Argument strings. */
343 Interp
*iPtr
= (Interp
*) interp
;
345 if ((argc
< 2) || (argc
> 4)) {
346 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
347 " message ?errorInfo? ?errorCode?\"", (char *) NULL
);
350 if ((argc
>= 3) && (argv
[2][0] != 0)) {
351 Tcl_AddErrorInfo(interp
, argv
[2]);
352 iPtr
->flags
|= ERR_ALREADY_LOGGED
;
355 Tcl_SetVar2(interp
, "errorCode", (char *) NULL
, argv
[3],
357 iPtr
->flags
|= ERROR_CODE_SET
;
359 Tcl_SetResult(interp
, argv
[1], TCL_VOLATILE
);
364 *----------------------------------------------------------------------
368 * This procedure is invoked to process the "eval" Tcl command.
369 * See the user documentation for details on what it does.
372 * A standard Tcl result.
375 * See the user documentation.
377 *----------------------------------------------------------------------
383 ClientData dummy
, /* Not used. */
384 Tcl_Interp
*interp
, /* Current interpreter. */
385 int argc
, /* Number of arguments. */
386 char **argv
/* Argument strings. */
393 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
394 " arg ?arg ...?\"", (char *) NULL
);
398 result
= Tcl_Eval(interp
, argv
[1], 0, (char **) NULL
);
402 * More than one argument: concatenate them together with spaces
403 * between, then evaluate the result.
406 cmd
= Tcl_Concat(argc
-1, argv
+1);
407 result
= Tcl_Eval(interp
, cmd
, 0, (char **) NULL
);
410 if (result
== TCL_ERROR
) {
412 sprintf(msg
, "\n (\"eval\" body line %d)", interp
->errorLine
);
413 Tcl_AddErrorInfo(interp
, msg
);
419 *----------------------------------------------------------------------
423 * This procedure is invoked to process the "expr" Tcl command.
424 * See the user documentation for details on what it does.
427 * A standard Tcl result.
430 * See the user documentation.
432 *----------------------------------------------------------------------
438 ClientData dummy
, /* Not used. */
439 Tcl_Interp
*interp
, /* Current interpreter. */
440 int argc
, /* Number of arguments. */
441 char **argv
/* Argument strings. */
445 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
446 " expression\"", (char *) NULL
);
450 return Tcl_ExprString(interp
, argv
[1]);
454 *----------------------------------------------------------------------
458 * This procedure is invoked to process the "for" Tcl command.
459 * See the user documentation for details on what it does.
462 * A standard Tcl result.
465 * See the user documentation.
467 *----------------------------------------------------------------------
473 ClientData dummy
, /* Not used. */
474 Tcl_Interp
*interp
, /* Current interpreter. */
475 int argc
, /* Number of arguments. */
476 char **argv
/* Argument strings. */
482 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
483 " start test next command\"", (char *) NULL
);
487 result
= Tcl_Eval(interp
, argv
[1], 0, (char **) NULL
);
488 if (result
!= TCL_OK
) {
489 if (result
== TCL_ERROR
) {
490 Tcl_AddErrorInfo(interp
, "\n (\"for\" initial command)");
495 result
= Tcl_ExprBoolean(interp
, argv
[2], &value
);
496 if (result
!= TCL_OK
) {
502 result
= Tcl_Eval(interp
, argv
[4], 0, (char **) NULL
);
503 if (result
== TCL_CONTINUE
) {
505 } else if (result
!= TCL_OK
) {
506 if (result
== TCL_ERROR
) {
508 sprintf(msg
, "\n (\"for\" body line %d)", interp
->errorLine
);
509 Tcl_AddErrorInfo(interp
, msg
);
513 result
= Tcl_Eval(interp
, argv
[3], 0, (char **) NULL
);
514 if (result
== TCL_BREAK
) {
516 } else if (result
!= TCL_OK
) {
517 if (result
== TCL_ERROR
) {
518 Tcl_AddErrorInfo(interp
, "\n (\"for\" loop-end command)");
523 if (result
== TCL_BREAK
) {
526 if (result
== TCL_OK
) {
527 Tcl_ResetResult(interp
);
533 *----------------------------------------------------------------------
537 * This procedure is invoked to process the "foreach" Tcl command.
538 * See the user documentation for details on what it does.
541 * A standard Tcl result.
544 * See the user documentation.
546 *----------------------------------------------------------------------
552 ClientData dummy
, /* Not used. */
553 Tcl_Interp
*interp
, /* Current interpreter. */
554 int argc
, /* Number of arguments. */
555 char **argv
/* Argument strings. */
558 int listArgc
, i
, result
;
562 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
563 " varName list command\"", (char *) NULL
);
568 * Break the list up into elements, and execute the command once
569 * for each value of the element.
572 result
= Tcl_SplitList(interp
, argv
[2], &listArgc
, &listArgv
);
573 if (result
!= TCL_OK
) {
576 for (i
= 0; i
< listArgc
; i
++) {
577 if (Tcl_SetVar(interp
, argv
[1], listArgv
[i
], 0) == NULL
) {
578 Tcl_SetResult(interp
, "couldn't set loop variable", TCL_STATIC
);
583 result
= Tcl_Eval(interp
, argv
[3], 0, (char **) NULL
);
584 if (result
!= TCL_OK
) {
585 if (result
== TCL_CONTINUE
) {
587 } else if (result
== TCL_BREAK
) {
590 } else if (result
== TCL_ERROR
) {
592 sprintf(msg
, "\n (\"foreach\" body line %d)",
594 Tcl_AddErrorInfo(interp
, msg
);
601 ckfree((char *) listArgv
);
602 if (result
== TCL_OK
) {
603 Tcl_ResetResult(interp
);
609 *----------------------------------------------------------------------
613 * This procedure is invoked to process the "format" Tcl command.
614 * See the user documentation for details on what it does.
617 * A standard Tcl result.
620 * See the user documentation.
622 *----------------------------------------------------------------------
628 ClientData dummy
, /* Not used. */
629 Tcl_Interp
*interp
, /* Current interpreter. */
630 int argc
, /* Number of arguments. */
631 char **argv
/* Argument strings. */
634 register char *format
; /* Used to read characters from the format
636 char newFormat
[40]; /* A new format specifier is generated here. */
637 int width
; /* Field width from field specifier, or 0 if
639 int precision
; /* Field precision from field specifier, or 0
640 * if no precision given. */
641 int size
; /* Number of bytes needed for result of
642 * conversion, based on type of conversion
643 * ("e", "s", etc.) and width from above. */
644 char *oneWordValue
= NULL
; /* Used to hold value to pass to sprintf, if
645 * it's a one-word value. */
646 double twoWordValue
; /* Used to hold value to pass to sprintf if
647 * it's a two-word value. */
648 int useTwoWords
; /* 0 means use oneWordValue, 1 means use
650 char *dst
= interp
->result
; /* Where result is stored. Starts off at
651 * interp->resultSpace, but may get dynamically
652 * re-allocated if this isn't enough. */
653 int dstSize
= 0; /* Number of non-null characters currently
655 int dstSpace
= TCL_RESULT_SIZE
;
656 /* Total amount of storage space available
657 * in dst (not including null terminator. */
658 int noPercent
; /* Special case for speed: indicates there's
659 * no field specifier, just a string to copy. */
660 char **curArg
; /* Remainder of argv array. */
661 int useShort
; /* Value to be printed is short (half word). */
664 * This procedure is a bit nasty. The goal is to use sprintf to
665 * do most of the dirty work. There are several problems:
666 * 1. this procedure can't trust its arguments.
667 * 2. we must be able to provide a large enough result area to hold
668 * whatever's generated. This is hard to estimate.
669 * 2. there's no way to move the arguments from argv to the call
670 * to sprintf in a reasonable way. This is particularly nasty
671 * because some of the arguments may be two-word values (doubles).
672 * So, what happens here is to scan the format string one % group
673 * at a time, making many individual calls to sprintf.
677 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
678 " formatString ?arg arg ...?\"", (char *) NULL
);
683 for (format
= argv
[1]; *format
!= 0; ) {
684 register char *newPtr
= newFormat
;
686 width
= precision
= useTwoWords
= noPercent
= useShort
= 0;
689 * Get rid of any characters before the next field specifier.
690 * Collapse backslash sequences found along the way.
693 if (*format
!= '%') {
697 oneWordValue
= p
= format
;
698 while ((*format
!= '%') && (*format
!= 0)) {
699 if (*format
== '\\') {
700 *p
= Tcl_Backslash(format
, &bsSize
);
711 size
= p
- oneWordValue
;
716 if (format
[1] == '%') {
717 oneWordValue
= format
;
725 * Parse off a field specifier, compute how many characters
726 * will be needed to store the result, and substitute for
727 * "*" size specifiers.
733 while ((*format
== '-') || (*format
== '#')) {
738 if (*format
== '0') {
743 if (isdigit(*format
)) {
744 width
= atoi(format
);
747 } while (isdigit(*format
));
748 } else if (*format
== '*') {
752 if (Tcl_GetInt(interp
, *curArg
, &width
) != TCL_OK
) {
760 sprintf(newPtr
, "%d", width
);
761 while (*newPtr
!= 0) {
765 if (*format
== '.') {
770 if (isdigit(*format
)) {
771 precision
= atoi(format
);
774 } while (isdigit(*format
));
775 } else if (*format
== '*') {
779 if (Tcl_GetInt(interp
, *curArg
, &precision
) != TCL_OK
) {
786 if (precision
!= 0) {
787 sprintf(newPtr
, "%d", precision
);
788 while (*newPtr
!= 0) {
792 if (*format
== 'l') {
794 } else if (*format
== 'h') {
815 newPtr
[-1] = tolower(*format
);
823 if (Tcl_GetInt(interp
, *curArg
, (int *) &oneWordValue
)
830 oneWordValue
= *curArg
;
831 size
= strlen(*curArg
);
834 if (Tcl_GetInt(interp
, *curArg
, (int *) &oneWordValue
)
841 newPtr
[-1] = tolower(newPtr
[-1]);
847 if (Tcl_GetDouble(interp
, *curArg
, &twoWordValue
) != TCL_OK
) {
852 if (precision
> 10) {
858 "format string ended in middle of field specifier";
861 sprintf(interp
->result
, "bad field specifier \"%c\"", *format
);
869 * Make sure that there's enough space to hold the formatted
870 * result, then format it.
877 if ((dstSize
+ size
) > dstSpace
) {
881 newSpace
= 2*(dstSize
+ size
);
882 newDst
= (char *) ckalloc((unsigned) newSpace
+1);
884 memcpy((VOID
*) newDst
, (VOID
*) dst
, dstSize
);
886 if (dstSpace
!= TCL_RESULT_SIZE
) {
893 memcpy((VOID
*) (dst
+dstSize
), (VOID
*) oneWordValue
, size
);
898 sprintf(dst
+dstSize
, newFormat
, twoWordValue
);
899 } else if (useShort
) {
900 int tmp
= (int)oneWordValue
;
901 sprintf(dst
+dstSize
, newFormat
, (short)tmp
);
903 sprintf(dst
+dstSize
, newFormat
, oneWordValue
);
905 dstSize
+= strlen(dst
+dstSize
);
909 interp
->result
= dst
;
910 if (dstSpace
!= TCL_RESULT_SIZE
) {
911 interp
->freeProc
= (Tcl_FreeProc
*) free
;
913 interp
->freeProc
= 0;
918 interp
->result
= "not enough arguments for all format specifiers";
920 if (dstSpace
!= TCL_RESULT_SIZE
) {