TIP #265: A CONVENIENT C-SIDE COMMAND OPTION PARSER FOR TCL ============================================================= Version: $Revision: 1.7 $ Author: Sam Bromley State: Final Type: Project Tcl-Version: 8.6 Vote: Done Created: Monday, 03 April 2006 URL: https://tip.tcl-lang.org265.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== The Tk C library provides developers with a /Tk_ParseArgv/() function that allows command line parsing of options of the "-option" form. Archived discussions on and on the Wiki indicate that a desire for similar functionality without Tk has arisen several times in the past. This TIP presents a Tk-free implementation of /Tk_ParseArgv()/ named *Tcl_ParseArgvObj*, that developers can use to parse "-option" style command options in C implementations of Tcl commands using the Tcl_Obj interface. RATIONALE =========== While the parsing of command options can be readily accomplished on the Tcl side, a uniform method for parsing "-option" formed options does not exist on the C side. Many developers are familiar with the ease of use of libpopt-style command line parsing, but a similarly clean method does not currently exist in Tcl. The common approach is to use /Tcl_GetIndexFromObj/(), yet this method alone does not allow the flexibilty and ease of use of libpopt-style parsing. One drawback of the classical /Tcl_GetIndexFromObj/()-only approach is the need to handle the specifies of your command option parsing for each unique command. This leads to significant code duplication. A libpopt-style approach is to bundle all of your parsing specifics into a single array of structures capturing the details, and then let a specific parsing routine handle the parsing of every option for you. The *Tcl_ParseArgvObj*() routine introduced in this TIP provides this functionality, thereby allowing the removal of all parsing specifics from the command implimentation other than that necessary to describe each optional argument. Additionally, a function *Tcl_ParseArgsObjv* is provided to provide the functionality of /Tk_ParseArgs/() to those who desire it. A discussion in 2002 on [] indicated that this is a desired feature. Arguments against a *Tcl_ParseArgsObjv* implementation include that it is better to do all command line parsing on the Tcl side. However, this implies writing two wrapper functions: (i) A C implementation of a Tcl command; and (ii) A Tcl wrapper that pre-parses the options before calling the C command. This can lead to significant duplication of effort when porting a large project to a Tcl enabled version. This point is particularly relevent in the context of *Tcl_ParseArgvObj*(), as then one is not assuming that one can simply replace the main() routine with Tcl, but rather that one is truly embedding the C side in a larger system. *Tcl_ParseArgvObj*() offers a clean method to enable flexible command line parsing to C implementations of Tcl commands. SPECIFICATION =============== This document proposes adding *Tcl_ParseArgsObjv*, whose arguments shall be: int *Tcl_ParseArgsObjv*(Tcl_Interp */interp/, const Tcl_ArgvInfo */argTable/, int */objcPtr/, Tcl_Obj *const */objv/, Tcl_Obj ***/remainingObjv/) *Note* that the count of arguments (referred to by /objcPtr/) will be modified, and a modified array will be returned via /remainingObjv/ (and need *ckfree*ing). The input array of objects will not be modified. REFERENCE IMPLEMENTATION ========================== A working implementation has been submitted to the Feature Request Tracker at SourceForge []. EXAMPLE OF USE ================ #include #include /* not needed if subsumed into core */ int g_test_cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *gname,*filename; int i; int numRepeat; double scalar; int doErase = 0; size_t size; /* this table specifies the possible options, all in one place.*/ Tcl_ArgvInfo argTable[] = { {"-erase", TCL_ARGV_CONSTANT, (void *) 1, &doErase, "erase image before plotting"}, {"-numRepeat", TCL_ARGV_INT, NULL, &numRepeat, "number of times to repeat test"}, {"-scalar", TCL_ARGV_FLOAT, NULL, &scalar, "scalar multiple to use for test"}, {"-outfile", TCL_ARGV_STRING, NULL, &filename, "name of file to which to dump result"}, {NULL, TCL_ARGV_END, NULL, NULL, NULL} }; /* Call Tcl_ParseArgObjv to do all the parsing! */ if (Tcl_ParseArgsObjv(interp,argTable,&objc,objv,&private_objv) != TCL_OK) { return TCL_ERROR; } /* Should recheck objc here */ /* at this point, any unhandled options are repacked in private_objv */ gname = Tcl_GetString(private_obj[1]); /* all done */ ckfree(private_objv); /* rest of code continues here...*/ return TCL_OK; } COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows