Tcl_GetIndexFromObj

Tcl_GetIndexFromObj is a C function in the Tcl C API.

Documentation: https://www.tcl-lang.org/man/tcl8.5/TclLib/GetIndex.htm


This function is useful when you need to tell what subcommand or other predefined argument has been given by the user. Let's assume, you have a typical command procedure in C:

int myCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    /* some useful code here */
}

Now, if the Tcl level command, that is processed here, has some keyword-like argument, e.g. [myTclCmd start], [myTclCmd stop], and [myTclCmd rewind], use Tcl_GetIndexFromObj like this:

int myCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[[]]) {
    /* the following array lists all keywords and is terminated by a NULL element */
    /**** NOTE: MUST BE static!! See notes below ****/
    static const char *subCmds[] = {"start", "stop", "rewind", NULL};
    /* the following enumeration reflects the array and allows to use the index, which is assigned in Tcl_GetIndexFromObj */
    enum keywordIdx {startIdx, stopIdx, rewindIdx};
    
    /* this will take the first argument given to the Tcl level command
       and compare it with the keywords listed in subCmds.
       If there is no match, and error is raised and an error message
       is automatically generated with the word ‘action’ -> bad action "...": must be start, stop, or rewind
       If there is a match, the index of the matched item in the arry is assigned to the ‘index’ variable */
    int index;
    if (Tcl_GetIndexFromObj(interp, objv[1], subCmds, "action", 0, &index) != TCL_OK) {
        return TCL_ERROR;
    }
    
    /* now use the enumeration to do your work depending on the keyword */
    switch (index) {
        case startIdx:
            /* do the start action */
            break;
        case stopIdx:
            /* do the stop action */
            break;
        case rewindIdx:
            /* do rewind action here */
            break;
    }
    return TCL_OK;
}

AMG: Why must subCmds be static? Making it static improves performance and memory use a little bit, but I can't imagine this code not working if subCmds isn't static, unless it's so huge it doesn't fit in the stack.

APN: See the documentation for the tablePtr parameter in the man page. Basically the pointer is held on to in the intrep of the object.


This function is frequently used in conjunction with Tcl_WrongNumArgs.