/* * tclCmdAH.c -- * * This file contains the top-level command routines for most of * the Tcl built-in commands whose names begin with the letters * A to H. * * Copyright (c) 1987-1993 The Regents of the University of California. * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifndef lint static char sccsid[] = "@(#) tclCmdAH.c 1.94 94/08/09 11:42:53"; #endif #include "tclInt.h" /* *---------------------------------------------------------------------- * * Tcl_BreakCmd -- * * This procedure is invoked to process the "break" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_BreakCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { if (argc != 1) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "\"", (char *) NULL); return TCL_ERROR; } return TCL_BREAK; } /* *---------------------------------------------------------------------- * * Tcl_CaseCmd -- * * This procedure is invoked to process the "case" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CaseCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int i, result; int body; char *string; int caseArgc, splitArgs; char **caseArgv; if (argc < 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " string ?in? patList body ... ?default body?\"", (char *) NULL); return TCL_ERROR; } string = argv[1]; body = -1; if (strcmp(argv[2], "in") == 0) { i = 3; } else { i = 2; } caseArgc = argc - i; caseArgv = argv + i; /* * If all of the pattern/command pairs are lumped into a single * argument, split them out again. */ splitArgs = 0; if (caseArgc == 1) { result = Tcl_SplitList(interp, caseArgv[0], &caseArgc, &caseArgv); if (result != TCL_OK) { return result; } splitArgs = 1; } for (i = 0; i < caseArgc; i += 2) { int patArgc, j; char **patArgv; register char *p; if (i == (caseArgc-1)) { interp->result = "extra case pattern with no body"; result = TCL_ERROR; goto cleanup; } /* * Check for special case of single pattern (no list) with * no backslash sequences. */ for (p = caseArgv[i]; *p != 0; p++) { if (isspace(UCHAR(*p)) || (*p == '\\')) { break; } } if (*p == 0) { if ((*caseArgv[i] == 'd') && (strcmp(caseArgv[i], "default") == 0)) { body = i+1; } if (Tcl_StringMatch(string, caseArgv[i])) { body = i+1; goto match; } continue; } /* * Break up pattern lists, then check each of the patterns * in the list. */ result = Tcl_SplitList(interp, caseArgv[i], &patArgc, &patArgv); if (result != TCL_OK) { goto cleanup; } for (j = 0; j < patArgc; j++) { if (Tcl_StringMatch(string, patArgv[j])) { body = i+1; break; } } ckfree((char *) patArgv); if (j < patArgc) { break; } } match: if (body != -1) { result = Tcl_Eval(interp, caseArgv[body]); if (result == TCL_ERROR) { char msg[100]; sprintf(msg, "\n (\"%.50s\" arm line %d)", caseArgv[body-1], interp->errorLine); Tcl_AddErrorInfo(interp, msg); } goto cleanup; } /* * Nothing matched: return nothing. */ result = TCL_OK; cleanup: if (splitArgs) { ckfree((char *) caseArgv); } return result; } /* *---------------------------------------------------------------------- * * Tcl_CatchCmd -- * * This procedure is invoked to process the "catch" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CatchCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int result; if ((argc != 2) && (argc != 3)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " command ?varName?\"", (char *) NULL); return TCL_ERROR; } result = Tcl_Eval(interp, argv[1]); if (argc == 3) { if (Tcl_SetVar(interp, argv[2], interp->result, 0) == NULL) { Tcl_SetResult(interp, "couldn't save command result in variable", TCL_STATIC); return TCL_ERROR; } } Tcl_ResetResult(interp); sprintf(interp->result, "%d", result); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ConcatCmd -- * * This procedure is invoked to process the "concat" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ConcatCmd(dummy, i