📄 itcl_ensemble.c
字号:
GetEnsemblePartUsage(ensData->parts[i], resultPtr); } Tcl_SetObjResult(interp, resultPtr); return TCL_ERROR; } /* * Found a match. Return the desired part. */ *rensPart = ensData->parts[pos]; return TCL_OK;}/* *---------------------------------------------------------------------- * * FindEnsemblePartIndex -- * * Searches for a part name within an ensemble. The part name * must be an exact match for an existing part name in the * ensemble. This procedure is useful for managing (i.e., * creating and deleting) parts in an ensemble. * * Results: * If an exact match is found, this procedure returns * non-zero, along with the index of the part in posPtr. * Otherwise, it returns zero, along with an index in posPtr * indicating where the part should be. * * Side effects: * None. * *---------------------------------------------------------------------- */static intFindEnsemblePartIndex(ensData, partName, posPtr) Ensemble *ensData; /* ensemble being searched */ char *partName; /* name of desired part */ int *posPtr; /* returns: index for part */{ int pos = 0; int first, last; int cmp; /* * Search for the desired part name. * All parts are in lexicographical order, so use a * binary search to find the part quickly. */ first = 0; last = ensData->numParts-1; while (last >= first) { pos = (first+last)/2; if (*partName == *ensData->parts[pos]->name) { cmp = strcmp(partName, ensData->parts[pos]->name); if (cmp == 0) { break; /* found it! */ } } else if (*partName < *ensData->parts[pos]->name) { cmp = -1; } else { cmp = 1; } if (cmp > 0) { first = pos+1; } else { last = pos-1; } } if (last >= first) { *posPtr = pos; return 1; } *posPtr = first; return 0;}/* *---------------------------------------------------------------------- * * ComputeMinChars -- * * Compares part names on an ensemble's part list and * determines the minimum number of characters needed for a * unique abbreviation. The parts on either side of a * particular part index are compared. As long as there is * a part on one side or the other, this procedure updates * the parts to have the proper minimum abbreviations. * * Results: * None. * * Side effects: * Updates three parts within the ensemble to remember * the minimum abbreviations. * *---------------------------------------------------------------------- */static voidComputeMinChars(ensData, pos) Ensemble *ensData; /* ensemble being modified */ int pos; /* index of part being updated */{ int min, max; char *p, *q; /* * If the position is invalid, do nothing. */ if (pos < 0 || pos >= ensData->numParts) { return; } /* * Start by assuming that only the first letter is required * to uniquely identify this part. Then compare the name * against each neighboring part to determine the real minimum. */ ensData->parts[pos]->minChars = 1; if (pos-1 >= 0) { p = ensData->parts[pos]->name; q = ensData->parts[pos-1]->name; for (min=1; *p == *q && *p != '\0' && *q != '\0'; min++) { p++; q++; } if (min > ensData->parts[pos]->minChars) { ensData->parts[pos]->minChars = min; } } if (pos+1 < ensData->numParts) { p = ensData->parts[pos]->name; q = ensData->parts[pos+1]->name; for (min=1; *p == *q && *p != '\0' && *q != '\0'; min++) { p++; q++; } if (min > ensData->parts[pos]->minChars) { ensData->parts[pos]->minChars = min; } } max = strlen(ensData->parts[pos]->name); if (ensData->parts[pos]->minChars > max) { ensData->parts[pos]->minChars = max; }}/* *---------------------------------------------------------------------- * * HandleEnsemble -- * * Invoked by Tcl whenever the user issues an ensemble-style * command. Handles commands of the form: * * <ensembleName> <partName> ?<arg> <arg>...? * * Looks for the <partName> within the ensemble, and if it * exists, the procedure transfers control to it. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything * goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error * message as the result in the interpreter. * *---------------------------------------------------------------------- */static intHandleEnsemble(clientData, interp, objc, objv) ClientData clientData; /* ensemble data */ Tcl_Interp *interp; /* current interpreter */ int objc; /* number of arguments */ Tcl_Obj *CONST objv[]; /* argument objects */{ Ensemble *ensData = (Ensemble*)clientData; int i, result; Command *cmdPtr; EnsemblePart *ensPart; char *partName; int partNameLen; Tcl_Obj *cmdlinePtr, *chainObj; int cmdlinec; Tcl_Obj **cmdlinev; /* * If a part name is not specified, return an error that * summarizes the usage for this ensemble. */ if (objc < 2) { Tcl_Obj *resultPtr = Tcl_NewStringObj( "wrong # args: should be one of...\n", -1); GetEnsembleUsage(ensData, resultPtr); Tcl_SetObjResult(interp, resultPtr); return TCL_ERROR; } /* * Lookup the desired part. If an ambiguous abbrevition is * found, return an error immediately. */ partName = Tcl_GetStringFromObj(objv[1], &partNameLen); if (FindEnsemblePart(interp, ensData, partName, &ensPart) != TCL_OK) { return TCL_ERROR; } /* * If the part was not found, then look for an "@error" part * to handle the error. */ if (ensPart == NULL) { if (FindEnsemblePart(interp, ensData, "@error", &ensPart) != TCL_OK) { return TCL_ERROR; } if (ensPart != NULL) { cmdPtr = (Command*)ensPart->cmdPtr; result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); return result; } } if (ensPart == NULL) { return Itcl_EnsembleErrorCmd((ClientData)ensData, interp, objc-1, objv+1); } /* * Pass control to the part, and return the result. */ chainObj = Tcl_NewObj(); chainObj->bytes = NULL; chainObj->typePtr = &itclEnsInvocType; chainObj->internalRep.twoPtrValue.ptr1 = (VOID *) ensPart; Tcl_IncrRefCount(objv[1]); chainObj->internalRep.twoPtrValue.ptr2 = (VOID *) objv[0]; Tcl_IncrRefCount(objv[0]); cmdlinePtr = Tcl_NewListObj(0, (Tcl_Obj**)NULL); Tcl_ListObjAppendElement((Tcl_Interp*)NULL, cmdlinePtr, chainObj); for (i=2; i < objc; i++) { Tcl_ListObjAppendElement((Tcl_Interp*)NULL, cmdlinePtr, objv[i]); } Tcl_IncrRefCount(cmdlinePtr); result = Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr, &cmdlinec, &cmdlinev); if (result == TCL_OK) { cmdPtr = (Command*)ensPart->cmdPtr; result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, cmdlinec, cmdlinev); } Tcl_DecrRefCount(cmdlinePtr); return result;}/* *---------------------------------------------------------------------- * * Itcl_EnsembleCmd -- * * Invoked by Tcl whenever the user issues the "ensemble" * command to manipulate an ensemble. Handles the following * syntax: * * ensemble <ensName> ?<command> <arg> <arg>...? * ensemble <ensName> { * part <partName> <args> <body> * ensemble <ensName> { * ... * } * } * * Finds or creates the ensemble <ensName>, and then executes * the commands to add parts. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything * goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error * message as the result in the interpreter. * *---------------------------------------------------------------------- */intItcl_EnsembleCmd(clientData, interp, objc, objv) ClientData clientData; /* ensemble data */ Tcl_Interp *interp; /* current interpreter */ int objc; /* number of arguments */ Tcl_Obj *CONST objv[]; /* argument objects */{ int status; char *ensName; EnsembleParser *ensInfo; Ensemble *ensData, *savedEnsData; EnsemblePart *ensPart; Tcl_Command cmd; Command *cmdPtr; Tcl_Obj *objPtr; /* * Make sure that an ensemble name was specified. */ if (objc < 2) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], (int*)NULL), " name ?command arg arg...?\"", (char*)NULL); return TCL_ERROR; } /* * If this is the "ensemble" command in the main interpreter, * then the client data will be null. Otherwise, it is * the "ensemble" command in the ensemble body parser, and * the client data indicates which ensemble we are modifying. */ if (clientData) { ensInfo = (EnsembleParser*)clientData; } else { ensInfo = GetEnsembleParser(interp); } ensData = ensInfo->ensData; /* * Find or create the desired ensemble. If an ensemble is * being built, then this "ensemble" command is enclosed in * another "ensemble" command. Use the current ensemble as * the parent, and find or create an ensemble part within it. */ ensName = Tcl_GetStringFromObj(objv[1], (int*)NULL); if (ensData) { if (FindEnsemblePart(interp, ensData, ensName, &ensPart) != TCL_OK) { ensPart = NULL; } if (ensPart == NULL) { if (CreateEnsemble(interp, ensData, ensName) != TCL_OK) { return TCL_ERROR; } if (FindEnsemblePart(interp, ensData, ensName, &ensPart) != TCL_OK) { panic("Itcl_EnsembleCmd: can't create ensemble"); } } cmdPtr = (Command*)ensPart->cmdPtr; if (cmdPtr->deleteProc != DeleteEnsemble) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "part \"", Tcl_GetStringFromObj(objv[1], (int*)NULL), "\" is not an ensemble", (char*)NULL); return TCL_ERROR; } ensData = (Ensemble*)cmdPtr->objClientData; } /* * Otherwise, the desired ensemble is a top-level ensemble. * Find or create the access command for the ensemble, and * then get its data. */ else { cmd = Tcl_FindCommand(interp, ensName, (Tcl_Namespace*)NULL, 0); if (cmd == NULL) { if (CreateEnsemble(interp, (Ensemble*)NULL, ensName) != TCL_OK) { return TCL_ERROR; } cmd = Tcl_FindCommand(interp, ensName, (Tcl_Namespace*)NULL, 0); } cmdPtr = (Command*)cmd; if (cmdPtr == NULL || cmdPtr->deleteProc != DeleteEnsemble) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "command \"", Tcl_GetStringFromObj(objv[1], (int*)NULL), "\" is not an ensemble", (char*)NULL); return TCL_ERROR; } ensData = (Ensemble*)cmdPtr->objClientData; } /* * At this point, we have the data for the ensemble that is * being manipulated. Plug this into the parser, and then * interpret the rest of the arguments in the ensemble parser. */ status = TCL_OK; savedEnsData = ensInfo->ensData; ensInfo->ensData = ensData; if (objc == 3) { /* CYGNUS LOCAL - fix for Tcl8.1 */#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 status = Tcl_EvalObj(ensInfo->parser, objv[2], 0);#else status = Tcl_EvalObj(ensInfo->parser, objv[2]);#endif } else if (objc > 3) { objPtr = Tcl_NewListObj(objc-2, objv+2); Tcl_IncrRefCount(objPtr); /* stop Eval trashing it */#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 status = Tcl_EvalObj(ensInfo->parser, objPtr, 0);#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -